实用指南:打造可用的迷你人工智能助手的代理、工具与技能
《实用指南》操作流程详解:适用于构建可运行迷你 AI 助手的代理、工具与技能;同时为采用该架构的团队提供合同模板、校验机制以及可直接插入的代码片段。
本指南将逐步构建从原材料到可运行系统的完整流程,涵盖用于构建功能型迷你人工智能助手的智能体、工具及技能。重点在于可操作的步骤、明确的检查点,以及可直接放入代码仓库的代码,无需猜测其用途。 在概览阶段,应在修改代码之前明确输入参数、各步骤的负责人以及完成标准。操作人员应能够从已知的检查点重新运行相应步骤,而无需推测隐藏状态。 除了功能结果外,还需记录执行时间以及令牌或查询成本。提前了解成本情况,可避免在流程从演示环境过渡到共享环境时出现意外费用。
什么是工具、技能和智能体?
在完成“什么是工具技能”这一阶段时,首先写下相关约定:所需的输入参数、成功标志以及部分失败时的处理方式。这样的清单能确保后续的代码修改保持透明。 将配置信息与应用程序代码分开存放。环境文件、密钥存储以及功能开关应集中于一个位置,这样操作人员无需查看整个系统结构即可进行审计。 为每次调用记录工具名称、参数哈希值、延迟时间以及执行结果。如果没有这些记录,调试代理将陷入无止境的循环,耗费大量时间。
get_current_conditions
get_forecast
get_alerts
get_historical_weather
get_air_quality
get_marine_conditions
get_river_conditions
get_wildfire_info
search_location
check_service_status
Temperature = Celsius, Fahrenheit, Kelvin
Length / Distance = Inches, Feet, Yards, Miles, Millimeters, Centimeters, Meters, Kilometers
Mass / Weight = Ounces, Pounds, Stone, Grams, Kilograms, Metric Tons
Volume / Capacity = Fluid Ounces, Cups, Pints, Quarts, Gallons, Milliliters, Liters, Cubic Meters
Area = Square Feet, Square Meters, Acres, Hectares
Speed = Miles per Hour (mph), Kilometers per Hour (km/h), Knots, Meters per Second (m/s)
Time Zones = UTC/GMT offsets, Daylight Saving Time (DST) transitions, Unix timestamps to human-readable dates
Storage = Bytes, Kilobytes (KB), Megabytes (MB), Gigabytes (GB), Terabytes (TB)
使用示例代码进行实验。
在“使用示例代码进行实验”阶段,首先需明确约定:所需的输入参数、成功信号以及部分失败时的处理方式。这样的检查清单能确保后续的代码修改始终符合约定。 同时记录正常流程和异常恢复流程。重试机制、人工审核环节以及错误消息处理都是产品功能的一部分,而非后续需要补充的内容。 需为每次调用记录工具名称、参数哈希值、延迟时间以及执行结果。没有这些记录,调试过程将会浪费大量时间。
步骤1 — 导入所需库
在处理“步骤1:导入阶段”时,首先需明确相关规范:所需输入、成功标志以及部分失败时的处理方式。这样的清单能确保后续的代码修改始终符合预期。 建议使用小型、可测试的单元而非庞大的脚本。当某个步骤失败时,故障应指向单一责任点,而非复杂的流程链。 需为每次调用记录工具名称、参数哈希值、延迟时间以及执行结果。没有这些记录,调试过程将会浪费大量时间。 在处理“步骤1:导入阶段”时,首先需明确相关规范:所需输入、成功标志以及部分失败时的处理方式。这样的清单能确保后续的代码修改始终符合预期。 除了功能结果外,还需记录执行时间以及令牌或查询成本。提前了解成本情况,可避免在从演示环境过渡到共享环境时出现意外费用。
import re
import os
import getpass
import requests
第2步 — 创建计算器工具
将第2步的创建阶段视为可度量的对象来处理效果最佳。在扩大范围之前,需记录一个成功的案例、一个失败案例以及回滚说明。 配置应置于应用程序代码之外。环境文件、密钥存储和功能标志应集中存放,以便操作人员无需查看整个系统结构即可进行审计。 以简洁的架构和明确的副作用标签来暴露工具功能。主机需要在自动批准之前知道哪些调用会修改状态。
def calculator_tool(prompt: str) -> str:
print(" [Tool 1: Calculator] scanning prompt for dollar amounts...")
dollar_amounts = re.findall(r'\$\s?(\d+(?:\.\d{1,2})?)', prompt)
if not dollar_amounts:
result = "no dollar amounts found"
print(f" [Tool 1: Calculator] {result}")
return result
values = [float(a) for a in dollar_amounts]
total = sum(values)
breakdown = " + ".join(f"${v:g}" for v in values)
result = f"{breakdown} = ${total:.2f}"
print(f" [Tool 1: Calculator] found {len(values)} amount(s) {values} -> {result}")
return result
第3步 — 创建单位转换器工具
将第三步“创建测试场景”视为可度量的表面来处理效果最佳。在扩大范围之前,先记录一个成功的用例、一个失败案例以及回滚说明。同时记录正常流程和恢复流程。重试机制、人工审核环节以及死信处理都是产品的一部分,而非后续需要补充的内容。应提供具有明确结构规范和清晰副作用标签的工具,这样主机在自动批准之前就能知道哪些调用会改变状态。
UNIT_ALIASES = {
"kilometers": "km", "kilometer": "km", "km": "km",
"mile": "miles", "miles": "miles",
"m": "meters", "meter": "meters", "meters": "meters",
"ft": "feet", "foot": "feet", "feet": "feet",
}
DISTANCE_TO_MILES = {"km": 0.621371, "miles": 1.0, "meters": 0.000621371, "feet": 0.000189394}
def unit_converter_tool(prompt: str) -> str:
print(" [Tool 2: Unit Converter] scanning prompt for distance legs...")
legs = re.findall(r'(\d+(?:\.\d+)?)\s*(kilometers?|km|miles?|meters?|feet|ft)\b',
prompt, re.IGNORECASE)
if not legs:
result = "no distances found"
print(f" [Tool 2: Unit Converter] {result}")
return result
total_miles = 0.0
breakdown = []
for value, unit in legs:
value = float(value)
unit_norm = UNIT_ALIASES.get(unit.lower(), unit.lower())
total_miles += value * DISTANCE_TO_MILES.get(unit_norm, 1.0)
breakdown.append(f"{value:g} {unit_norm}")
result = f"{' + '.join(breakdown)} = {round(total_miles, 2)} miles total"
print(f" [Tool 2: Unit Converter] found {len(legs)} leg(s) -> {result}")
return result
第四步 — 创建总结技能
将“第4步:创建阶段”视为可度量的工作面时效果最佳。在扩大范围之前,需记录一份理想运行案例、一个故障案例以及回滚说明。 相比庞大的脚本,应优先选择小型且可测试的单元。当某一步骤出现故障时,故障原因应能指向单一责任模块,而非复杂的流程链。 应使用具有明确结构规范和清晰副作用标注的工具。在自动批准之前,主机需要知道哪些调用会修改状态。 将“第4步:创建阶段”视为可度量的工作面时效果最佳。在扩大范围之前,需记录一份理想运行案例、一个故障案例以及回滚说明。 除了功能结果外,还需记录执行时间以及令牌或查询成本。提前了解成本情况,可避免在从演示环境过渡到共享环境时出现意外费用。
def summarizer_skill(text: str, max_sentences: int = 2) -> str:
print(" [Skill: Summarizer] scanning message for key sentence(s)...")
sentences = [s for s in re.split(r'(?<=[.!?])\s+', text.strip()) if s]
if len(sentences) <= max_sentences:
print(f" [Skill: Summarizer] only {len(sentences)} sentence(s) -- returning as-is")
return text.strip()
stopwords = {"the","a","an","is","are","was","were","in","on","at","to","of","and",
"or","for","it","this","that","i","you","he","she","they","we","really"}
words = re.findall(r'\b\w+\b', text.lower())
freq = {}
for w in words:
if w not in stopwords:
freq[w] = freq.get(w, 0) + 1
scored = []
for idx, sentence in enumerate(sentences):
s_words = re.findall(r'\b\w+\b', sentence.lower())
score = sum(freq.get(w, 0) for w in s_words)
scored.append((score, idx, sentence))
top = sorted(scored, key=lambda x: x[0], reverse=True)[:max_sentences]
top_in_order = sorted(top, key=lambda x: x[1])
summary = " ".join(s for _, _, s in top_in_order)
print(f" [Skill: Summarizer] kept {len(top_in_order)} of {len(sentences)} sentence(s) -> {summary}")
return summary
第5步 — 连接到你的LLM
在第五步“连接到阶段”中,应在修改代码之前明确输入参数、该步骤的负责人以及结束标准。操作人员应能够从已知的检查点重新运行该步骤,而无需猜测隐藏状态。 配置信息应置于应用程序代码之外。环境文件、密钥存储以及功能标志应集中存放于一个位置,以便操作人员无需查看整个流程即可进行审计。 当下一步是代码执行或工具调用时,优先使用具有架构验证的结构化输出,而非自由形式的文本描述。
GROQ_API_KEY = os.environ.get("GROQ_API_KEY") or getpass.getpass(
"Enter your free Groq API key (from https://console.groq.com/keys), "
"or press Enter to skip: "
)
GROQ_MODEL = "openai/gpt-oss-20b"
GROQ_ENDPOINT = "https://api.groq.com/openai/v1/chat/completions"
def call_llm(augmented_prompt: str,
system_prompt: str = "You are a helpful, concise assistant.") -> str:
if not GROQ_API_KEY:
return ("[No LLM reply -- no Groq API key was provided. Get a free one at "
"https://console.groq.com/keys, then re-run the setup cell above.]\n"
f"Here is the augmented prompt that would have been sent:\n\"\"\"\n{augmented_prompt}\n\"\"\"")
try:
response = requests.post(
GROQ_ENDPOINT,
headers={
"Content-Type": "application/json",
"Authorization": f"Bearer {GROQ_API_KEY}",
},
json={
"model": GROQ_MODEL,
"messages": [
{"role": "system", "content": system_prompt},
{"role": "user", "content": augmented_prompt},
],
"temperature": 0.7,
"max_tokens": 400,
},
timeout=30,
)
response.raise_for_status()
data = response.json()
return data["choices"][0]["message"]["content"].strip()
except requests.exceptions.RequestException as e:
return f"[LLM request failed -- {e}]"
except (KeyError, IndexError, ValueError):
return "[LLM returned an unexpected response format.]"
print("LLM configured." if GROQ_API_KEY else "No key entered -- running in fallback mode.")
第六步 — 构建你的智能体
在第六步“构建你的阶段”中,应在修改代码之前明确输入参数、该步骤的负责人以及结束标准。操作人员应能够从已知的检查点重新运行该步骤,而无需猜测隐藏状态。 需同时记录正常流程和异常恢复流程。重试机制、人工审核环节以及错误消息处理都是产品本身的组成部分,而非后续需要补充的功能。 在网关处进行身份验证,在数据层进行重新授权。仅凭承载令牌并不能作为租户边界。
def show_step(step_num: int, label: str, content: str) -> None:
"""Small helper so every agent prints its pipeline the same, readable way."""
print(f"\n STEP {step_num} - {label}:")
for line in str(content).splitlines() or [""]:
print(f" {line}")
def trip_planner_agent(prompt: str) -> str:
"""Agent 1. Condition: 2+ dollar costs AND 2+ distances -- a multi-stop itinerary."""
print("[Router] -> Agent 1: Trip Planner Agent activated (detected an itinerary: multiple costs + multiple distances)")
show_step(1, "Original prompt", prompt)
cost_result = calculator_tool(prompt)
show_step(2, "Tool result (Calculator -- total cost)", cost_result)
distance_result = unit_converter_tool(prompt)
show_step(3, "Tool result (Unit Converter -- total distance)", distance_result)
augmented_prompt = (
f"The user asked: \"{prompt}\"\n\n"
f"A calculator tool already computed the total cost: {cost_result}\n"
f"A distance tool already computed the total distance traveled: {distance_result}\n\n"
"Using those two verified totals (don't redo either calculation yourself), give the "
"user a short, friendly trip summary that reports both totals clearly."
)
show_step(4, "Prompt has changed -- now the augmented prompt sent to the LLM", augmented_prompt)
reply = call_llm(augmented_prompt)
show_step(5, "Final response from Groq", reply)
return f"🧳 Agent 1: Trip Planner Agent:\n{reply}"
def text_agent(prompt: str) -> str:
"""Agent 2. Condition: default for any prompt, OR chained after Agent 1
when the itinerary prompt also has an extra narrative sentence."""
print("[Router] -> Agent 2: Text Analysis Agent activated")
show_step(1, "Original prompt", prompt)
summary = summarizer_skill(prompt)
show_step(2, "Skill result (Summarizer)", summary)
augmented_prompt = (
f"The user wrote: \"{prompt}\"\n\n"
f"Automatic summary of their message: {summary}\n\n"
"Write a short, thoughtful, natural-sounding reply to the user that responds "
"to what they actually said, informed by (but not just repeating) this summary."
)
show_step(3, "Prompt has changed -- now the augmented prompt sent to the LLM", augmented_prompt)
reply = call_llm(augmented_prompt)
show_step(4, "Final response from Groq", reply)
return f"📝 Agent 2: Text Analysis Agent:\n{reply}"
第七步 —— 导航至正确的代理
在将第7步流程投入使用之前,需先明确输入参数、该步骤的负责人以及结束标准,然后再进行代码修改。操作人员应能够从已知的检查点重新运行该步骤,而无需猜测其中的隐藏状态。 相较于庞大的脚本,应优先选择小型且易于测试的单元。当某一步骤失败时,故障原因应能明确指向某个具体的责任模块,而非整个复杂的流程。 在网关处进行身份验证,在数据层再次授权。仅凭承载令牌并不足以界定租户边界。 在将第7步流程投入使用之前,需先明确输入参数、该步骤的负责人以及结束标准,然后再进行代码修改。操作人员应能够从已知的检查点重新运行该步骤,而无需猜测其中的隐藏状态。 除了功能结果外,还需记录执行时间以及令牌或查询的成本。提前了解成本情况,可避免在流程从演示环境过渡到共享环境时出现意外账单。
def looks_like_itinerary(prompt: str) -> bool:
dollar_amounts = re.findall(r'\$\s?\d+(?:\.\d{1,2})?', prompt)
distance_legs = re.findall(r'\d+(?:\.\d+)?\s*(?:kilometers?|km|miles?|meters?|feet|ft)\b',
prompt, re.IGNORECASE)
return len(dollar_amounts) >= 2 and len(distance_legs) >= 2
def has_extra_narrative(prompt: str) -> bool:
sentences = [s for s in re.split(r'(?<=[.!?])\s+', prompt.strip()) if s]
extra = [
s for s in sentences
if "quot; not in s
and not re.search(r'\b(?:miles?|km|kilometers?|feet|ft)\b', s, re.IGNORECASE)
and not s.strip().endswith("?")
]
return len(extra) >= 1
def route_prompt(prompt: str) -> str:
if looks_like_itinerary(prompt):
reply = trip_planner_agent(prompt)
if has_extra_narrative(prompt):
print("[Router] -> also routing to Agent 2: Text Analysis Agent (extra narrative sentence detected)")
reply += "\n\n" + text_agent(prompt)
return reply
else:
return text_agent(prompt)
第8步 —— 测试结果
在执行第8步“测试”时,首先需记录下相关约定:所需的输入参数、成功信号以及部分失败时的处理方式。这样的检查清单能确保后续的代码修改不会偏离原有设计。 应将配置信息与应用程序代码分开存放。环境文件、密钥存储以及功能开关应集中于一个位置,这样操作人员无需查看整个系统结构即可进行审计。 需为每次调用记录工具名称、参数哈希值、延迟时间以及最终结果。如果没有这些记录,调试过程将会浪费大量时间。
prompt = input("Ask me anything: ")
print("=" * 60)
print(f"PROMPT: {prompt}")
print("=" * 60)
final_answer = route_prompt(prompt)
print(f"\n >>> RETURNED: {final_answer}")
print("-" * 60 + "\n")
理解逻辑结构
在“理解逻辑”阶段,首先写下契约内容:所需的输入参数、成功信号以及部分失败时会发生什么。这样的检查清单能确保后续的代码修改保持一致性。 同时记录正常流程和异常恢复流程。重试机制、人工审核环节以及死信处理都是产品本身的组成部分,而非后续需要补充的功能。 需为每次调用记录工具名称、参数哈希值、延迟时间以及最终结果。没有这些记录,调试代理时将会浪费大量时间。
第一步 — 路由到代理
在完成“第一步:将路由功能接入阶段”的工作时,首先需明确相关规范:所需的输入参数、成功信号以及部分失败时的处理方式。这份清单能确保后续的代码修改始终符合预期。 相比冗长的脚本,更应采用小型且可测试的单元。当某一步骤失败时,故障应指向单一责任模块,而非复杂的流程链。 需为每次调用记录工具名称、参数哈希值、延迟时间以及执行结果。若没有这些记录,调试过程将会浪费大量时间。 在完成“第一步:将路由功能接入阶段”的工作时,首先需明确相关规范:所需的输入参数、成功信号以及部分失败时的处理方式。这份清单能确保后续的代码修改始终符合预期。 除了功能结果外,还需记录执行耗时以及代币或查询成本。提前了解成本情况,可避免在功能从演示环境过渡到共享环境时出现意外费用。
第二步 —— 规划代理调用其工具
将第二步的行程规划阶段视为可度量的对象来处理,效果最佳。在扩大范围之前,需记录一个成功的案例、一个失败案例以及回滚说明。 应将配置与应用程序代码分开。环境文件、密钥存储和功能标志应集中存放于一处,以便操作人员无需查看整个系统结构即可进行审计。 需提供具有明确数据结构和清晰副作用标签的工具。主机需要在自动批准之前知道哪些调用会改变系统状态。
第三步 — 调用计算工具
将“第三步:调用阶段”视为可度量的对象来处理效果最佳。在扩大范围之前,先记录一个成功的案例、一个失败案例以及回滚说明。同时记录正常流程和恢复流程。重试机制、人工审核环节以及死信处理都是产品本身的一部分,而非后续需要补充的内容。应提供具有明确结构规范和清晰副作用标签的工具,这样主机在自动批准之前就能知道哪些调用会改变状态。
第四步 — 调用单元转换工具
将“第4步:调用阶段”视为可度量的操作面时,其效果最佳。在扩大范围之前,需记录一份理想的执行日志、一个失败案例以及回滚说明。 相比庞大的脚本,应优先使用小型且可测试的单元。当某一步骤失败时,故障应指向单一责任模块,而非复杂的流程链。 应使用结构明确的工具,并标注清晰的副作用。主机需要在自动批准之前知道哪些调用会修改状态。 将“第4步:调用阶段”视为可度量的操作面时,其效果最佳。在扩大范围之前,需记录一份理想的执行日志、一个失败案例以及回滚说明。 除了功能结果外,还需记录执行时间以及令牌或查询成本。提前了解成本情况,可避免在从演示环境过渡到共享环境时出现意外费用。
第5步 — 创建更新后的提示词
在第五步“创建更新后的阶段”中,应在修改代码之前明确输入参数、该步骤的负责人以及结束标准。操作人员应能够从已知的检查点重新运行该步骤,而无需猜测隐藏状态。 配置信息应置于应用程序代码之外。环境文件、密钥存储以及功能标志应集中存放于一个位置,这样操作人员无需查看整个系统结构即可进行审核。 当下一步是代码执行或工具调用时,应优先使用具有架构验证的结构化输出,而非自由形式的文本描述。
第六步 —— 将结果发送至 GROQ
在第六步“发送结果”阶段,应在修改代码之前明确输入参数、该步骤的负责人以及结束标准。操作人员应能够从已知的检查点重新运行该步骤,而无需猜测隐藏状态。需同时记录正常流程和异常恢复流程。重试机制、人工审核环节以及死信处理都是产品功能的一部分,而非后续需要补充的内容。应在网关处进行身份验证,在数据层再次授权——仅凭承载令牌并不能作为租户边界。
第七步 — 使用text_agent
在“步骤7:使用textagent”阶段,修改代码之前需先定义输入参数、该步骤的负责人以及结束标准。操作人员应能够从已知的检查点重新运行该步骤,而无需猜测其中的隐藏状态。相比冗长的脚本,更应采用小型且可测试的单元。当某个步骤失败时,故障原因应能明确指向某个特定责任方,而非整个复杂的流程。应在网关处进行身份验证,在数据层再次授权——仅凭承载令牌并不足以界定租户边界。在“步骤7:使用textagent”阶段,修改代码之前需先定义输入参数、该步骤的负责人以及结束标准。操作人员应能够从已知的检查点重新运行该步骤,而无需猜测其中的隐藏状态。除了功能结果外,还应记录执行时间以及令牌或查询的成本。提前了解成本情况,可避免在流程从演示环境转向共享环境时出现意外账单。
第8步——使用总结功能
在执行第8步“使用总结”阶段时,首先写下相关约定:所需的输入参数、成功标志以及部分失败时的处理方式。这样的清单能确保后续的代码修改保持一致性。 将配置信息置于应用程序代码之外。环境文件、密钥存储以及功能开关应集中存放于一个位置,这样操作人员无需查看整个系统结构即可进行审计。 为每次调用记录工具名称、参数哈希值、延迟时间以及执行结果。如果没有这些记录,调试代理将陷入无止境的循环,耗费大量时间。
第9步——再次将结果发送到GROQ
在执行第9步“发送结果”阶段时,首先写下相关契约:所需的输入参数、成功信号以及部分失败时的处理方式。这样的检查清单能确保后续的代码修改不会偏离原定方向。 同时记录正常流程和异常恢复流程。重试机制、人工审核环节以及死信处理都是产品本身的组成部分,而非后续需要补充的功能。 需为每次调用记录工具名称、参数哈希值、延迟时间以及最终结果。没有这些记录,调试代理时往往会浪费大量时间。
阐述使用代理、技能和工具的必要性。
在撰写“为阶段设计提供依据”的内容时,首先需明确合同条款:所需输入、成功标志以及部分失败时的处理方式。这样的清单能确保后续的代码修改保持透明。 相比冗长的脚本,应优先选择小型且可测试的单元。当某个步骤失败时,故障应指向单一责任点,而非复杂的流程链。 需为每次调用记录工具名称、参数哈希值、延迟时间以及最终结果。没有这些记录,调试循环将会耗费大量时间。 在撰写“为阶段设计提供依据”的内容时,首先需明确合同条款:所需输入、成功标志以及部分失败时的处理方式。这样的清单能确保后续的代码修改保持透明。 在功能结果旁还需记录执行时间以及令牌或查询成本。提前了解成本情况,可避免在从演示环境过渡到共享环境时出现意外费用。
操作检查清单
将操作检查清单阶段视为可度量的标准,效果最佳。在扩大范围之前,先记录一份完美的操作日志、一个故障案例以及回滚说明。
把这一阶段视为输入与已验证输出之间的契约。为相关文档命名,明确成功标准,绝不允许默许不完整的操作。
使用具有严格结构定义且带有明确副作用标注的工具。主机需要在自动批准之前知道哪些调用会改变系统状态。
对于涉及资金支出或修改生产数据的操作,必须经过人工审批。编译时的连接方式并不等同于业务上的完整性。
编写简短的操作手册:包括如何轮换密钥、如何清空队列、以及如何回滚上一次的导入操作。
同时记录正常流程和故障恢复流程。重试机制、人工审核环节以及死信处理都是产品不可或缺的部分,而非后续需要补充的内容。
在推广该技术栈之前,应先冻结版本、为关键流程记录标准输出日志,并明确回滚步骤。共享环境需要设置速率限制、租户验证机制,以及负责密钥轮换的明确责任人。与其展示花哨的一次性演示,不如追求扎实可靠的性能。
关于6caa2a29578e的批处理说明:请将提供商密钥移出代码仓库,设定单会话令牌上限,并将日志存储在评估用示例文件旁,以便后续模型更换时仍能保持对比性。