6.2 Agent 与工作流构建


6.2 Agent 与工作流构建

本节摘要:Agent 与工作流的分野在于控制权在谁手上——工作流由代码编排,每步调用一次模型;Agent 由模型决策,循环"思考-调工具-观察"直到自认完成。本节先用结构化输出实现一个真正能执行动作的本地 Agent 循环,再给出该模式在 CLI、LangChain、n8n 三种载体上的落地形态,最后讲清本地小模型做 Agent 的能力边界与补偿手法。

从"会聊天"到"会做事"的关键一步

让模型做事,缺的不是智力而是输出接口:模型只能吐文本,而程序需要确定的结构。Ollama 的 JSON Schema 约束(4.2 节)恰好补上这块——把"下一步动作"强制成合法 JSON,Agent 循环就有了可靠的地基。设计三种动作:finish(给出最终答案)、think(陈述当前推理,不产生外部效果)、tool(调用指定工具并附参数)。

import json, ollama TOOLS = { "read_file": lambda p: open(p, encoding="utf-8").read()[:2000], "run_shell": lambda c: __import__("subprocess").run( c, shell=True, capture_output=True, text=True, timeout=30).stdout[:2000], "list_dir": lambda p: "\n".join(__import__("os").listdir(p)), } ACTION_SCHEMA = { "type": "object", "properties": { "action": {"type": "string", "enum": ["think", "tool", "finish"]}, "tool": {"type": "string", "enum": list(TOOLS)}, "args": {"type": "string"}, "answer": {"type": "string"}, "thought": {"type": "string"}, }, "required": ["action"], } def agent(goal, max_steps=8): messages = [ {"role": "system", "content": "你是执行助手。每一步只输出一个 JSON 动作:需要外部信息用 tool," "信息足够后用 finish 给出最终答案。"}, {"role": "user", "content": goal}, ] for _ in range(max_steps): out = ollama.chat(model="qwen2.5:7b", messages=messages, format=ACTION_SCHEMA, options={"temperature": 0}, stream=False) act = json.loads(out["message"]["content"]) print(">>", act) if act["action"] == "finish": return act.get("answer", "") if act["action"] == "tool": result = TOOLS[act["tool"]](act.get("args", "")) messages.append({"role": "assistant", "content": json.dumps(act, ensure_ascii=False)}) messages.append({"role": "user", "content": f"工具结果:\n{result}"}) return "步数耗尽,未完成。" print(agent("统计当前目录下有多少个 .md 文件,并告诉我其中最大文件的名字"))

跑起来会看到模型先 list_dir,再 run_shell 执行 ls -lS *.md | head -1,最后 finish 汇报结论——这就是 ReAct 模式的最小完整实现,全部依赖只有 ollama 库。

Agent 与工作流:选哪个

代码固定流程、模型只做单步判断的,是工作流:输入→分类→分支处理→汇总,每步 prompt 独立可测,失败可重试,行为可预期。任务路径不定、需要模型自己拆解探索的,才是 Agent:自主决定查什么、调什么、何时收尾,灵活但不可预期。工程铁律:能工作流就别 Agent——确定性问题套 Agent 循环是自找麻烦;真正开放的任务("排查这个服务为什么慢")才值得交出控制权。

同一套"结构化输出 + 工具表"思想在三类载体上的形态:

# 载体一:纯 shell,cron 里跑的无人值守工作流 ollama run qwen2.5:7b "把以下告警分类为 P0/P1/P2,只输出级别:$ALERT_TEXT" \ | while read lvl; do [ "$lvl" = "P0" ] && notify_oncall; done
# 载体二:LangChain 的 Ollama 接入(工具循环由框架托管) from langchain_ollama import ChatOllama llm = ChatOllama(model="qwen2.5:7b", temperature=0) resp = llm.invoke([("user", "把'下周一'解析成 ISO 日期,只输出日期")]) print(resp.content)

载体三是 n8n / Dify 这类可视化编排:HTTP 节点指向 Ollama 的 /api/chat,配合 format 字段做结构化分支,适合不会写代码的团队把模型嵌进审批、工单流程。

本地小模型做 Agent 的现实约束与补偿

7B-14B 模型当决策核心,有三条硬约束。其一,长循环里指令漂移——跑到第五步忘了目标。对策:把目标复述进每轮 system 提示词,并在消息过长时压缩早期工具结果。其二,格式失误率高于云端大模型——schema 约束能保证合法 JSON,但参数填错(文件名拼错、命令幻觉)仍会发生。对策:工具返回尽量带"可用项列表"(先 list_dirread_file,而不是让模型直接猜路径);危险工具(shell)套白名单或人工确认。其三,规划深度浅——超过三四步的推理链容易断。对策:把 Agent 限制在窄域(运维巡检、日志排查、数据查询),并在 finish 前强制要求一次自检("逐条核对答案是否有工具结果支撑")。

安全底线再强调一次:工具权限按最小化授予,shell 类默认拒绝、文件写入限目录、外网访问可关则关。Agent 的能力边界就是你授予的工具边界。

下一节离开纯文本世界,看看模型如何直接理解图像——多模态应用的三种典型玩法。


作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U