普通对话是一问一答:用户输入,模型输出,结束。Agent 则是一个循环:
这个循环里,模型扮演“大脑”,工具是“手脚”,程序是“神经”。关键点在于:模型不再直接给出最终答案,而是给出下一步动作。 这也是 Agent 容易出错的地方——动作选错、参数编错、陷入死循环,都需要工程手段兜底。
一个可用的 Agent 通常包含四部分:
工具描述是常被低估的一环。模型选错工具,往往不是因为它“笨”,而是因为工具描述含糊。例如“搜索”这个工具,如果描述只写“搜索信息”,模型可能拿它去搜本地文件;写成“在互联网上搜索实时公开信息,不用于查询本地数据”,歧义就少很多。
下面是一个精简示例,演示 Agent 的核心循环。代码省略了错误处理和重试,只保留骨架。
import json, os
from openai import OpenAI
client = OpenAI(api_key=os.getenv("API_KEY"), base_url=os.getenv("BASE_URL"))
TOOLS = [{
"type": "function",
"function": {
"name": "get_weather",
"description": "查询指定城市的实时天气,仅用于天气问题",
"parameters": {
"type": "object",
"properties": {"city": {"type": "string"}},
"required": ["city"],
},
},
}]
def get_weather(city: str) -> str:
return f"{city}:晴,26℃" # 示例实现,实际应调用天气 API
def run_agent(question: str, max_steps: int = 5) -> str:
messages = [{"role": "user", "content": question}]
for _ in range(max_steps):
resp = client.chat.completions.create(
model="your-model-name", messages=messages, tools=TOOLS
)
msg = resp.choices[0].message
if not msg.tool_calls:
return msg.content
messages.append(msg)
for call in msg.tool_calls:
args = json.loads(call.function.arguments)
result = get_weather(**args)
messages.append({
"role": "tool",
"tool_call_id": call.id,
"content": result,
})
return "达到最大步数,任务未完成"
print(run_agent("北京今天天气怎么样?"))这段代码体现了 Agent 的几个要点:工具用结构化 schema 声明、模型返回工具调用而不是直接回答、程序执行后把结果以 tool 消息回填、用 max_steps 防止死循环。最后这一点尤其重要,没有步数上限的 Agent 在生产环境里是危险的。
实践中,Agent 有几种典型模式。ReAct 模式让模型交替进行推理和行动,适合需要多步探索的任务;规划—执行模式先让模型拆解任务清单,再逐项执行,适合步骤明确的长任务;多智能体模式让多个角色分工协作,适合复杂流程,但成本和调试难度显著上升。对大多数场景,单 Agent 加几个好工具已经够用,不必一上来就追求多智能体。
工程上要注意几点。第一,工具要幂等、可超时、可回滚,因为模型可能重复调用同一工具。第二,权限要最小化,删除文件、发送邮件、转账这类动作必须加人工确认。第三,要有可观测性,记录每一步的模型输入输出和工具结果,否则出了问题无从排查。第四,评估要自动化,准备一批任务和期望结果,定期回归测试,避免改一个提示词就悄悄退化。
Agent 的本质不是更聪明的模型,而是一个带工具、带循环、带边界的执行框架。模型负责决策,工具负责行动,程序负责约束和兜底。本文的最小循环只有几十行,却已经包含了 Agent 的全部关键要素:工具 schema、循环、结果回填和步数上限。先把这条链路跑通,再逐步加入重试、日志、权限和评估,才是稳妥的落地路径。从“会聊天”到“会干活”,中间隔的不是更大的模型,而是一个设计良好的循环。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。