agent的全景认知和一个node沙盒小工具
一、AI 认知模型全景视图
┌─────────────────────────────────────────────────────────────┐
│ 应用层 (Application) │
│ Manus · ClawBot · 垂直领域 Agent │
├─────────────────────────────────────────────────────────────┤
│ 编排层 (Orchestration) │
│ Dify(低代码) · LangChain(编程框架) · LangGraph(状态机) │
├─────────────────────────────────────────────────────────────┤
│ 记忆层 (Memory) │
│ Vector DB · RAG · 上下文压缩 · 长期记忆机制 · Milvus │
├─────────────────────────────────────────────────────────────┤
│ 模型层 (Foundation Model) │
│ GPT-4o · Claude · DeepSeek · 多模态大模型 │
└─────────────────────────────────────────────────────────────┘
未来的 AI 应用不是「大模型单打独斗」,而是「记忆 + 规划 + 工具」的认知架构竞争。
我们该在未来的 AI 时代中何去何从?我认为是借助 AI 的能力,去实现类似于 ClawBot 这种 AI 应用,解决模型到落地的最后一公里问题。
二、认识模型:从 DeepSeek 的开放平台开始
这里会给大家介绍两个平台:
- DeepSeek 开放平台:api-docs.deepseek.com/zh-cn/参数较少,适合初步认知。
- 阿里云百炼:阿里云百炼控制台 类似 OpenAI,模型丰富、支持自定义调试,文档详细,适合高自定义、多 Agent 协作等场景。
一般会有 Base API(用于访问模型),需要填入生成的 API Key(密钥)。根据所用框架或编排工具,选择对应的模型名,如 DeepSeek 的 Chat 模型与 Reasoner 模型,各有侧重点。
除此之外,一般还会有**温度(Temperature)**设置,可以理解为模型的「创意开关」或「发散程度调节器」,核心是概率分布的尖锐度。
温度越低,模型越像「严谨的老师」;温度越高,模型越像「喝醉的诗人」。
| 温度值 | 特征 | 典型应用 | 输出特点 |
|---|---|---|---|
| 0 - 0.3 | 确定性/保守 | 代码生成、数学计算、知识问答、JSON | 事实准确、逻辑严谨,可能机械、缺乏变化 |
| 0.4 - 0.7 | 平衡 | 通用对话、写作辅助、商业文案 | 正确性与自然流畅度兼顾 |
| 0.8 - 1.2 | 创造性 | 创意写作、头脑风暴、诗歌、角色扮演 | 词汇丰富、想象力强,可能跑题 |
| > 1.5 | 混乱/发散 | 艺术实验、随机灵感、对抗性测试 | 可能荒诞、跳跃、非逻辑 |
三、现代模型进化的四大共同趋势
- Agentic 能力(自主代理)所有模型都在强化工具调用链、多步骤规划、环境交互能力。Gartner 将 Agentic AI 列为 2025 年顶级战略技术趋势,预计年增长率 40%(来源)。
- 推理架构的显性化不再隐藏思考过程,而是提供「思考模式」(Thinking/Deep Think)开关,让用户在速度与深度间权衡,代表从模式匹配到结构化推理的范式转移。
- 上下文窗口的军备竞赛从 256K(Kimi)到 400K(GPT-5)再到 1M(Claude),目标都是实现**「整本书/整个代码库」的一次性处理**,降低对 RAG 精度的依赖。
- 垂直专业化与成本分层 同一模型家族内部分化出标准版(推理)、Mini 版(成本)、Nano 版(延迟),通过自动路由为用户匹配最优性价比。
以上是结合当前模型更新汇总的结论:主流模型主要在工具调用、推理架构、上下文、成本四个方向优化。
下文将围绕 AI 工具调用展开:为什么各大模型厂商都重视它,以及它由哪些解决方案组成。
对于生产级模型落地(而非简单 API 调用),记忆层和编排层是概念上必须经过的两大关卡。即使没有显式使用 Milvus 或 LangChain,系统也必然要实现这两层的等效功能(哪怕用代码硬编码)。这两者都是编码层面具有代表性的工具,我们可以不直接用,但需要理解其思想。
四、记忆层:解决「模型天生健忘」的硬伤
基础大模型是**无状态(Stateless)**的——每次 API 请求独立,不会记得 5 分钟前的对话,更无法记住上周的业务数据。
落地时必须处理的问题:
- 上下文稀缺:即便 GPT-5 支持 400K tokens,全量塞进上下文既贵又慢,且无法跨会话保持。
- 知识过时:模型训练数据有截止日期,需要 RAG 接入实时知识库。
- 个性化缺失:没有记忆层,每次对话从零开始,无法「越用越懂你」。
大量上下文会带来:一、干扰多,结论不精确;二、token 消耗大、分析时间更长;三、难以对企业内部资源做有效整合。
落地形态对比:
| 简单玩具 | 生产级落地 |
|---|---|
直接塞历史消息到 messages 参数 | 向量数据库(Milvus/Pinecone)存储海量文档 |
| 用全局变量存临时状态 | 长期记忆机制(如 MemGPT)管理记忆优先级 |
| 不管 token 消耗 | 上下文压缩(RAG 重排序、摘要机制)控制成本 |
本质:记忆层是让模型从「考试机器」变成「业务专家」的基础设施。没有它,模型只能回答通用问题,无法处理企业私有知识或保持连续性。我们下面主要来讲rag模式 还有history管理方案 这个则是在各个编排工具内各有内置的方案 我们在此不做深入研究
4.1 什么是 RAG(Retrieval Augmented Generation)
RAG(检索增强生成)结合了信息检索与文本生成,在大模型生成答案时利用外部知识库中的相关信息。效果由三个核心阶段决定:
引用:阿里云 RAG 检索说明
- 建立索引:知识的解析、切片与向量化。
- 检索召回:根据用户查询(Prompt),从向量存储中匹配并召回相关知识片段。
- 生成答案:大模型根据召回片段与用户查询,生成最终答案。
在 LangChain 官网,RAG 架构分为三种模式,层层递进。
4.2 RAG 流程一:建立索引(Indexing)
- **Loader(加载)**通过文档加载器加载文档,主要完成读取文件。
- Split(拆分)文本拆分器将大型
Document拆成更小的块,便于索引和放入模型有限的上下文窗口。若文档超过约 42000 字符,对多数模型过长;即使能塞进上下文,极长输入下也难定位关键信息,因此需要先切块再嵌入与存储。 - 存储 通过向量存储与嵌入模型将切分后的内容向量化并存入(如 Milvus),便于检索。
文本如何变成向量? 通过 Embeddings 模型将文本转为向量,再写入 Milvus 等向量数据库,供 AI 检索。
示例:
Dimension of embeddings: 1536
Input: 风急天高猿啸哀, embedding is: [-0.0016666285653348784, 0.008690492014557004, ...]
Input: 渚清沙白鸟飞回, embedding is: [0.018255604113922633, 0.030631669725945727, ...]
Input: 无边落木萧萧下, embedding is: [-0.01270165436681136, 0.011355212676752505, ...]
Input: 不尽长江滚滚来, embedding is: [0.003449439128962428, 0.02667092110022496, ...]
4.3 RAG 流程二:检索与生成 —— Agent 调用向量数据库
检索的本质:语义匹配
当用户问:「公司的年假怎么休?」
- 传统搜索:在数据库里找包含「年假」关键词的文档(可能漏掉「带薪休假」「年休假」等同义表达)。
- 向量检索:
- 把问题转成向量(Embedding),如
[0.023, -0.151, 0.892, ...](768 维或 1536 维)。 - 在 Milvus 中计算余弦相似度,找到向量距离最近的文本块。
- 返回 Top 5 最相关段落(即使没出现「年假」二字,语义相关也能找到)。
- 把问题转成向量(Embedding),如
把检索封装成「工具」(Tool)
Agent 默认没有查库能力,需要把检索包装成**工具(Tool)**才能调用。在提示词中说明:当问题属于某类时,使用向量数据库做相似度搜索,返回相关片段;Agent 整合搜索结果后,由大模型生成答案。向量库也可在此阶段加筛选条件,在百万级数据场景下很有用。
完成上述两步,即得到一个基础的 RAG 检索流程,在 LangChain 官网称为 2-Step RAG(两步检索增强生成)。
此外还有两种进阶方式:
-
**Agentic RAG(智能体检索增强生成)**由大模型判断是否需要文档/数据库查询、网络 API 等外部调用,再决定调用哪些工具。
-
Hybrid RAG(混合检索增强生成)在标准模式基础上加入多重校验:
- 对问题做评估(可调用 Agent/工具),若判断问题不合理则改写后重查;
- 对检索结果用 Agent 评估,不合标准则重新检索;
- 由 AI 自行判断错误并从对应节点重新开始。
4.4 三种 RAG 模式概览
方案 A:标准模式(2-Step RAG)
「先查资料,再回答」——简单直接。
工作流程:
- 用户提问:「今年的差旅报销标准是什么?」
- 系统自动在知识库找到《财务制度》第 3 章相关内容。
- AI 基于该内容生成回答,并标注来源。
核心价值:
- 快:固定流程,一次检索 + 一次生成,响应在 2 秒内。
- 省成本:步骤简单,调用 AI 次数少。
- 稳:结果可预测,不会「乱翻书」。
方案 B:智能模式(Agentic RAG)
「让 AI 自己决定要不要查资料」。
工作流程:
- 用户复杂提问:「对比我们公司和竞争对手在华东区的定价策略差异,并给出建议。」
- AI 自主分析:「需要分三步:先查内部定价表(工具1),再查竞品公开信息(工具2),最后做对比分析。」
- AI 按需调用多个工具,层层推进,最终生成报告。
核心价值:
- 灵活:复杂问题能「见招拆招」。
- 多工具协作:可查文档、计算器、数据库、实时网页等。
- 类人思维:先收集信息再下结论。
方案 C:质控模式(Hybrid RAG)
「查完还要验,错了就重来」——带质检的严谨方案。
工作流程:在标准模式基础上加入三重校验:
- 问题优化:用户问得模糊?先改写成更精准的问题(如把「那个谁」改为「张三」)。
- 检索验证:查到内容是否相关?若不相关,自动换关键词重查。
- 答案核查:生成回答是否符合事实?若有矛盾,重新生成或标注「存疑」。
核心价值:
- 风险可控:每步有校验,减少用错误信息作答。
- 自我修正:发现答非所问或信息不足时,可自主优化流程。
- 审计友好:全程可追溯,知道参考了哪些资料、为何这样答。
五、编排层
模型和记忆都有了,还要有人决定:什么时候调模型、什么时候查库、什么时候调工具、顺序怎么排——这一层就是编排层。好比上文的rag的生成 什么时候去查询向量数据库 如何对问题进行分析 如何评估搜寻的结果是否满意 我们需要借助编排工具去实现 ,当然 在下一层的manus 或者 clawbot (openclaw),他们并没有使用这里编排工具的一种,而是自己搭建的编排工具
5.1 主流编排工具对比(GitHub Stars 与优缺点)
以下为当前较主流的四类编排工具,兼顾可视化/低代码与编码/框架两种路线,便于按团队习惯选型。
| 工具 | 类型 | GitHub Stars | 优点 | 缺点 |
|---|---|---|---|---|
| Dify | 可视化 / 低代码平台 | 128k | 工作流 + RAG + Agent 一体;可视化画布、Prompt IDE;50+ 内置工具;Docker 一键部署、多模型支持;LLMOps 与观测完善 | 自托管需自行维护;企业级能力依赖商业版;偏「平台」思维,深度定制要理解其抽象 |
| LangChain | 编程框架(Python/JS) | 126k | 生态最大、文档与社区成熟;可编程、灵活度高;与 LangGraph、LangSmith 等配套;模型/向量库/工具集成丰富 | 学习曲线陡;版本迭代快、API 易变;偏开发者,无开箱即用的可视化编排 |
| AutoGen | 多智能体编程框架 | 54.2k | 多智能体对话与协作原生支持;微软背书;支持 MCP、AgentTool 等;提供 AutoGen Studio 可做低代码原型 | 官方建议新人关注 Microsoft Agent Framework;维护重心可能向新框架倾斜;纯代码编排需一定 Python 能力 |
| Coze Studio | 可视化 Agent 开发平台 | 19.7k | 脱胎于字节 Coze,一站式可视化;插件、知识库、工作流、API/SDK 齐全;Go 后端 + React/TS 前端,DDD 架构,便于二次开发 | 相对较新,生态小于 Dify/LangChain;需自建并配置模型;公有云能力与商业版有差异 |
选型参考:要快速搭 Demo、少写代码优先看 Dify 或 Coze Studio;要全代码控制、对接自有系统优先 LangChain / LangGraph;要做多 Agent 协作、研究向可看 AutoGen 或 LangGraph。
5.2 重点了解:Dify 与 LangChain
下文主要围绕 Dify 和 LangChain 两种编排方式展开,并举例说明各自适用场景。得益于 MCP 等协议的发展,两者并非互斥,而是形成很好的互补关系:
- 简单到中等复杂度的 AI 应用:适合用 Dify(可视化、少写代码、快速上线)。
- 高度复杂、强定制的应用:适合用 LangChain(全代码控制、深度集成业务、自定义链与 Agent)。
编排工具会不断更新、被更好的替代,但编排逻辑和AI 相关概念(记忆、分类、流式、并行、Agent 汇总等)是通用的——这些思想可以套用在 Dify 上,也值得长期学习。
5.3 Dify 简介:能帮我们做什么?
Dify 是低代码/可视化编排工具。借用官网描述:
Dify 是一个用于构建 AI 工作流的开源平台。通过在可视化画布上编排 AI 模型、连接数据源、定义处理流程,直接将你的领域知识转化为可运行的软件。
能力概览:支持本地化部署;可使用插件能力对接外部 API/数据库;通过模板节点输出结构化数据(如 JSON),便于前端或下游系统处理。了解这些,就能快速搭建以下几类场景。
5.4 Dify 场景示例
- 表单预填用户进入表单页时,调用插件查询近几次提交或用户偏好,经模板节点输出预填数据(如 JSON),前端解析后填充表单。要点:插件查数据 + 模板节点出结构化结果,方便对接。
- 文本片段补全根据前文内容补全后续文本。创建 Chatflow 并开启流式输出,用代码节点做后处理使输出更可控;用问题分类器节点将请求路由到最合适的场景;启用记忆,在分类与补全时带入对话历史,提高多轮准确性。实际可做成「每输入一段或停顿一段时间再触发补全」,以平衡体验与成本。
- 长文本汇总助手 文本量大时,用多个输入节点对长文分块、并发处理,最后汇聚到一个 Agent 节点做汇总。并发能缩短总耗时(整体处理速度/吞吐提升),并可能因分块聚焦而提高汇总质量。
以上示例体现了 Dify 中插件、模板、流式、分类、记忆、并行与汇聚等编排思想,这些概念在 LangChain 等框架中同样存在,只是实现方式从「画布拖拽」变成了「代码编排」。
5.5 LangChain 简介
LangChain 是编程优先的 AI 应用编排框架(支持 Python / JavaScript),通过代码组装模型、提示词、工具、记忆与向量库等组件,构建可复用的链(Chain)与智能体(Agent)。借用官网定位:
LangChain 是构建 LLM 应用的平台。它通过统一的接口连接模型、嵌入、向量存储、检索与工具等,让开发者快速从原型迭代到生产,并随技术演进保持可扩展。
与 Dify 的对比:Dify 用画布和节点完成编排,LangChain 用代码定义每一步——链式调用、条件分支、工具选择、多轮记忆等都由你显式控制,适合需要深度定制、对接自有系统或实现复杂 Agent 逻辑的场景。
核心概念速览:
- Chain:把提示词、模型、解析等步骤串成一条流水线(如 RAG 链:检索 → 拼上下文 → 调用模型 → 解析输出)。
- Agent:由模型根据当前输入决定「下一步调用哪个工具、传什么参数」,多步推理与工具调用循环进行。
- Tool:可被 Agent 调用的能力单元(查库、调 API、执行代码等),在 LangChain 中通常封装为函数并绑定到模型。
- Memory:在对话或链式调用中持久化/读取历史(如缓冲记忆、摘要记忆),供多轮对话或长流程使用。
下面列举 LangChain 的实际使用场景及简要实现思路。
- API 文档分析,生成 Mock 接口用 Chain 串联:解析文档(如 OpenAPI/Swagger)→ 提取路径、参数、响应结构 → 用 LLM 生成对应 Mock 数据或 Mock 服务代码;可配合模板和校验步骤,保证输出格式稳定。
- 低代码平台 AI 生成自定义组件用 Agent + Tool:把「读设计稿/需求描述」「查组件库 API」「写代码」「执行预览」封装成 Tool,由模型按需调用;多轮时可启用 Memory 记住已选组件和约束,保证风格一致。
- 自动化运维部署、仓库管理 用 Agent + Tool:将执行命令、读仓库状态、发 MR、查流水线等封装为 Tool,由 Agent 根据自然语言指令选择并执行;复杂流程可用 LangGraph 做有状态编排,或与现有 CI/CD 脚本对接。
延伸:以上场景都是「代码里显式定义每一步」,适合对可控性、可测试性和与现有系统集成要求高的场景。若需要快速出 Demo 或给业务方拖拽式配置,可先用 Dify 搭主流程,再用 LangChain(或通过 MCP 暴露的能力)承接复杂逻辑与自动化,二者形成互补。
六、AI 集成应用与 ClawBot 简介
前文提到的模型层、记忆层、编排层是「能力层」,最终要落到用户能直接使用的应用上。本节说明什么是 AI 集成应用,并以 ClawBot / OpenClaw 为例,说明它们与各层的关系、做了哪些创新,以及自研框架与 Dify/LangChain 等流行框架的异同。更详细的介绍可参考:知乎 · ClawBot 相关讨论。
6.1 什么是 AI 集成应用
AI 集成应用指的是:把模型层(推理)、记忆层(RAG/长期记忆)、编排层(何时调模型、何时查库、何时调工具)以及工具能力(填表、发邮件、跑脚本、控制设备等)打包成终端用户可直接使用的产品——例如聊天机器人、个人助理、垂直领域 Agent 等。用户不关心底层用的是哪家模型、哪套向量库,只关心「能对话、能办事、能记住我」。
与分层的关系可以简单理解为:
| 层次 | 作用 | 与「AI 集成应用」的关系 |
|---|---|---|
| 模型层 | 提供推理与生成能力 | 应用通过 API 调用模型,得到回复或决策 |
| 记忆层 | 存储与检索知识、对话历史、用户偏好 | 应用把「要记住什么」「要查什么」交给记忆层,再拼进上下文 |
| 编排层 | 决定调用顺序、分支、工具选择 | 应用要么使用现成编排工具(如 Dify、LangChain),要么自研编排逻辑(如 ClawBot) |
| 应用层 | 面向最终用户的产品形态 | AI 集成应用就站在这一层,整合下层能力,并通过 IM、Web、API 等渠道交付给用户 |
因此:AI 集成应用 = 在应用层,对模型层、记忆层、编排层(及工具)做整合后的可交付产品。ClawBot / OpenClaw 正是这一类产品——它们没有直接采用前文提到的 Dify 或 LangChain,而是自研了编排与技能体系,从而更贴合「个人助理 + 多渠道 + 本地优先」的定位。
6.2 ClawBot / OpenClaw 简介
ClawBot(后曾用名 Moltbot,开源版本常称 OpenClaw)是一类个人 AI 助手型集成应用,典型特点包括:
- 可执行实际操作:不限于聊天,能运行命令、填表格、发邮件、控制浏览器与智能家居等,充当「数字个人助理」。
- 多渠道集成:接入 WhatsApp、Telegram、iMessage、Slack、Discord 等,在用户日常使用的通讯工具里与用户交互,实现「像和真人对话一样」的使用方式。
- 对话记忆:能记住较长时间的对话内容,并支持主动提醒等能力,依赖自研或集成的记忆机制。
- 技能系统:通过 AgentSkills 兼容的技能(或类似插件)扩展能力,用户可从 ClawdHub 等技能库发现、安装、更新技能,形成可扩展生态。
这类产品把「模型 + 记忆 + 编排 + 工具」全部收口在一个应用里,用户看到的是「一个助理」,背后则是模型层、记忆层、编排层的协同。
6.3 与模型层、记忆层、编排层的关系
ClawBot / OpenClaw 作为应用层产品,与各层的关系可以概括为:
- 模型层:通过接入 OpenAI、Claude、DeepSeek 等厂商的 API,获得推理与生成能力;应用负责组请求、解析回复。
- 记忆层:采用自研记忆方案(例如用 Markdown 文本文件 存储 AGENTS.md、SOUL.md、MEMORY.md、每日记忆日志等),实现长期记忆与人格/行为设定;部分能力在概念上与 RAG/向量库类似,但实现方式更轻量、本地化。
- 编排层:并未使用 Dify、LangChain 等现成编排平台,而是自研编排与调度——例如通过 Gateway 控制平面统一管理消息通道、工具调用与事件触发,相当于「自建了一个小型编排引擎」,以便深度贴合 IM 接入、设备控制、技能加载等需求。
也就是说:他们站在应用层,自己实现了「何时调模型、何时查记忆、何时调哪个技能/工具」的逻辑,从而在架构上与「用 Dify 画布」或「用 LangChain 写链」形成差异:更垂直、更产品化,而不是通用编排平台。
6.4 他们做了什么创新
从公开资料与社区讨论中,可以归纳出以下几类创新点:
| 方向 | 说明 |
|---|---|
| 插件化 / 技能生态 | 从单体演进为插件化架构,模型提供商、技能等解耦为独立模块;通过 ClawdHub 等技能注册表,用户可发现、安装、更新技能,社区可贡献新能力,形成「应用 + 技能市场」的形态。 |
| Gateway 控制平面 | 消息通道、工具调用、事件触发由统一 Gateway 管理,类似「总控/接线员」,便于对接多种 IM 与设备,并统一做鉴权、限流、路由。 |
| 本地优先与记忆形态 | 本地优先策略,敏感数据可只存本地;记忆采用 Markdown 文件(如 AGENTS.md、MEMORY.md、每日日志),用户和开发者可直接查看、编辑,透明且可版本管理。 |
| 多渠道 + 7×24 待命 | 深度集成 IM,用户在常用聊天工具里即可与 AI 交互;结合自动化与记忆,实现「随时发消息、随时执行任务」的助理体验。 |
| 自动化执行深度 | 不限于「聊天 + 查知识」,而是真正执行操作:填表、发邮件、跑脚本、控制浏览器与智能家居等,把「工具调用」做成产品级能力。 |
这些创新集中在应用形态、编排自研、记忆形态、技能生态、渠道与执行深度上,与「只接一个模型 API」或「只用通用编排平台」的路线有明显区别。
6.5 自研框架与流行框架的异同
| 维度 | ClawBot / OpenClaw 自研路线 | Dify / LangChain 等流行框架 |
|---|---|---|
| 编排 | 自研:Gateway + 自建调度逻辑,不依赖 Dify/LangChain | 通用编排:Dify 画布、LangChain 链/Agent,可复用于多种应用 |
| 定位 | 应用层产品:直接面向终端用户(个人助理、IM 内使用) | 能力层/中间层:提供编排与集成能力,由业务再封装成应用 |
| 记忆 | 自研:Markdown 文件、本地优先,强调可控与可读 | 通用方案:多与向量库/RAG 集成,Dify/LangChain 均支持多种记忆与检索 |
| 扩展 | 技能/插件:ClawdHub、AgentSkills 兼容技能,围绕「一个应用」扩展 | Tool/插件/工作流:Dify 插件与工作流节点、LangChain Tool,围绕「编排能力」扩展 |
| 渠道与部署 | 深度集成 IM、本地优先、设备控制等,产品形态固定 | 渠道无关:多为 API/SDK,由接入方决定 Web/IM/内部系统等 |
| 底层逻辑 | 相同:仍是「模型 + 记忆 + 工具调用」的认知架构,只是编排与记忆的实现方式自研 | 相同:同样依赖模型 API、记忆/检索、工具调用,只是以通用框架形式提供 |
小结:ClawBot / OpenClaw 是应用层的 AI 集成应用,在模型层、记忆层、编排层之上做整合;创新点在于自研编排与技能体系、Gateway 控制平面、本地优先的记忆形态、以及多渠道 IM 与深度自动化执行;与 Dify/LangChain 的异同——底层思想一致(模型+记忆+工具),但不自建在现成编排平台上,而是自研框架以更好贴合「个人助理 + 多渠道 + 本地 + 技能生态」的产品目标。
七、沙箱插件功能实现
本节介绍 CLI 中「AI 沙箱」插件的功能与实现思路,便于对内分享。实现基于 LangChain 的 Tool 与 Agent 调用(LangChain Tools 概念),用自然语言驱动「生成代码 → 沙箱执行」的闭环。
7.1 沙箱的概念:为什么需要沙箱
沙箱(Sandbox) 在这里指:在一个隔离的运行时环境里执行由 AI 生成的代码,而不是直接在宿主进程里执行。
- 为什么要隔离:用户说「生成一个 index.html」或「把当前目录下所有 .txt 里的空格改成下划线」时,我们会让模型生成一段 JavaScript 代码,再由程序执行。若这段代码直接在宿主 Node 进程里跑,一旦模型生成
require('child_process').execSync('rm -rf /')或访问敏感环境变量,就会对真实系统造成风险。沙箱的作用是限制执行环境:只暴露我们允许的 API(如createFile、readFile、listDir),不暴露完整的require、process.env等,从而把「AI 生成的代码」和「真实系统」隔开。 - 本项目的沙箱实现:使用 vm2 库,把一段「沙箱全局对象」(包含
__workspace、fs、path、createFile、readFile等)注入到 VM 里,模型生成的代码只能访问这些对象;执行时用 IIFE 包裹代码以便支持顶层return,执行结果或异常由宿主捕获后返回给用户。这样既能让 AI「写代码办事」,又不会越权操作宿主。
7.2 功能概述
- 入口:
st sandbox <指令...>,例如st sandbox 生成一个 index.html、st sandbox 把当前目录下所有 .txt 里的空格改成下划线。 - 行为:根据用户指令,由调度模型决定是「执行代码/操作文件」还是「纯问答」;若需执行代码,则再调用一次模型,根据沙箱环境说明生成可在沙箱中运行的 JavaScript 代码,经语法校验后在 vm2 沙箱中执行,并将结果返回给用户。
- 特殊处理:若生成的代码会启动 HTTP 服务(如
app.listen),进程会挂起并提示「按 Ctrl+C 停止」,避免服务立刻退出。
7.3 整体流程与 LangChain 概念对应
| 步骤 | 实现 | LangChain 概念简述 |
|---|---|---|
| 1. 调度 | 模型根据用户输入决定调用 sandbox 还是 direct_answer | Tool:把能力封装成工具,模型通过 tool_calls 选择调用;bindTools 将工具绑定到模型。 |
| 2. 生成代码 | 沙箱工具内再调用一次模型,传入「沙箱环境说明」+ 用户指令,得到代码字符串 | SystemMessage / HumanMessage:构造对话;model.invoke(messages):同步调用模型。 |
| 3. 执行与回传 | 在 vm2 中执行代码,将 stdout/返回值拼成字符串,作为ToolMessage 回传给模型 | ToolMessage:工具执行结果必须用 tool_call_id 与之前的 tool_calls 对应,模型据此继续推理或结束。 |
多轮逻辑:命令里用 messages 数组累积 HumanMessage → AIMessage(含 tool_calls)→ ToolMessage → …,循环 model.invoke(messages) 直到模型不再发起 tool_calls,即完成一轮「调度 → 执行 → 回复」。
7.4 命令入口:调度 Agent 与工具循环
命令定义在 src/bin/command/agentCommand/sandbox.ts。核心:绑定两个 Tool,用系统提示词约束「何时调沙箱、何时直接回答」。
// 调度提示:需要动文件/跑代码 → sandbox;纯问答 → direct_answer
const DISPATCHER_SYSTEM_PROMPT = `你是调度助手:根据用户输入决定「要不要执行代码」,并只调用一个工具。
规则:
1. **需要执行代码/操作文件时** → 调用 \`sandbox\`,把用户的整句指令原样传入。
2. **纯问答、不需要动文件或跑代码时** → 调用 \`direct_answer\`,用 \`answer\` 参数给出简短回答(1~3 句话)。
3. 只调用一个工具,不要同时调用两个。`;
const tools = [sandboxTool, answerTool];
const model = createModel().bindTools(tools);
const messages = [new SystemMessage(DISPATCHER_SYSTEM_PROMPT), new HumanMessage(instruction)];
const response = await model.invoke(messages);
// 若有 response.tool_calls,则执行对应工具,把结果 push 成 ToolMessage,再 invoke(messages),循环
- bindTools(tools):LangChain 中把「可调用的工具列表」绑到模型上,模型输出中会包含 tool_calls(工具名 + 参数)。
- ToolMessage:构造时需传入 tool_call_id(与 AIMessage 中某条 tool_call 的 id 一致),这样模型才能把「这条工具结果」与「哪一次调用」对应起来。
7.5 Tools 如何写、为什么这么写
工具定义在 src/bin/langchain/tools/sandbox.ts。我们只暴露两个 Tool:direct_answer(纯问答)和 sandbox(执行代码/操作文件)。模型通过 tool_calls 选择调用哪一个,并传入对应参数。下面用实际代码说明怎么写以及为什么这么写。
7.5.1 为什么只有两个 Tool?
调度层只需要做二选一:「用户是在问问题」→ 用 direct_answer 直接回答;「用户要动文件或跑代码」→ 用 sandbox 生成代码并在沙箱里执行。若只给一个「万能工具」,模型容易在纯问答时也去调沙箱,增加延迟和误执行风险;若拆成很多小工具(如「创建文件」「读文件」「执行命令」),调度模型要做的选择太多,容易选错。因此两个工具、职责清晰,便于在系统提示词里写清「何时调哪个」。
7.5.2 answerTool:纯问答工具
import { tool } from "@langchain/core/tools";
import { z } from "zod";
export const answerTool = tool(
(args: { answer: string }) => args.answer,
{
name: "direct_answer",
description:
"仅用于纯问答:用户只是提问、解释、闲聊,不需要创建/修改/删除文件或执行任何代码时使用。回答必须简短(一两句话到一小段),不要长篇大论。",
schema: z.object({
answer: z.string().describe("简短回答,控制在 1~3 句话内,不要过长"),
}),
}
);
- name:模型在 tool_calls 里通过这个名字选中该工具;写成
direct_answer与调度提示词里的「调用direct_answer」一致。 - description:最关键。LangChain 会把 description 发给模型,模型据此判断「当前用户输入是否属于纯问答」。这里明确写了「仅用于纯问答」「不需要创建/修改/删除文件或执行任何代码」「回答必须简短」,模型才会在用户问「什么是 RAG」时调这个工具,而不是调 sandbox。
- schema:用 zod 声明参数。模型不会「自己发明」参数名,而是按 schema 里的字段生成 JSON;这里只有
answer一个字符串,模型就会把要回复给用户的话放进answer,我们直接args.answer返回即可。不写 schema 的话,模型不知道要传什么参数,容易不传或传错。
7.5.3 sandboxTool:沙箱执行工具
export const sandboxTool = tool(
async (args: { instruction: string }) => {
const { instruction } = args;
// 1. 构造沙箱专用对话,让模型生成代码
const messages = [
new SystemMessage(SANDBOX_SYSTEM_PROMPT),
new HumanMessage(instruction),
];
const res = await model.invoke(messages);
const responseText = typeof res.content === "string" ? res.content : String(res.content ?? "");
// 2. 解析代码 + 是否 HTTP 服务
const { code, isHttpService } = parseCodeFromResponse(responseText);
if (!code) return `未能从模型回复中解析出代码。...`;
// 3. Acorn 语法校验
const validation = validateSyntax(code);
if (!validation.ok) return `语法校验失败:${validation.message}`;
// 4. 在沙箱中执行
try {
const result = await runInSandbox(code);
// 格式化结果,若为 HTTP 服务则加前缀供命令层挂起进程
return isHttpService ? SANDBOX_HTTP_SERVICE_PREFIX + body : body;
} catch (err) {
return `沙箱执行错误:${msg}`;
}
},
{
name: "sandbox",
description:
"仅当用户需要「执行代码/操作文件」时使用:例如创建/修改/删除文件、生成 HTML、批量重命名、运行 shell 命令、读目录等。不需要动文件或跑代码时不要调用。",
schema: z.object({
instruction: z
.string()
.describe("用户的自然语言指令,例如:生成一个 index.html;或:把当前目录下所有 .txt 文件名里的空格改成下划线"),
}),
}
);
- name:
sandbox,与调度提示词里「调用sandbox」一致。 - description:明确写「仅当用户需要执行代码/操作文件时使用」,并举例(创建/修改/删除文件、生成 HTML、批量重命名、运行命令、读目录),最后强调「不需要动文件或跑代码时不要调用」。这样模型才会在用户说「生成一个 index.html」时调 sandbox,在用户说「什么是 RAG」时不调。
- schema:只有一个参数
instruction,类型为 string,describe 里给了示例。调度模型会把用户的整句指令原样放进instruction,sandboxTool 内部再拿这句 instruction 去调第二次模型(生成代码的那次),这样「调度」和「生成代码」解耦:调度只负责选工具+传参,生成代码由沙箱专用的 system prompt(SANDBOX_SYSTEM_PROMPT)约束。 - 为什么工具内部再调一次模型? 因为「生成可在沙箱中执行的 JavaScript」需要另一套提示词(沙箱环境说明、默认目录、HTTP 服务标记等),和「调度:选 sandbox 还是 direct_answer」的提示词不同。所以设计成:调度模型只做二选一并传
instruction;sandboxTool 内部用 SANDBOX_SYSTEM_PROMPT + instruction 再 invoke 一次模型,得到代码后再校验、执行、返回。这样职责清晰,也便于单独调优沙箱侧的提示词。
7.5.4 sandboxTool 内部四步(简要)
- 构造沙箱专用对话:
SystemMessage(SANDBOX_SYSTEM_PROMPT)+HumanMessage(instruction)。SANDBOX_SYSTEM_PROMPT 由getSandboxPromptContext("markdown")生成,限制模型只使用沙箱内列出的 API。 - 解析模型回复:从回复中提取 ```js ... ``` 或裸代码,并判断是否包含
__IS_HTTP_SERVICE__或代码中是否有.listen(,用于后续是否挂起进程。 - Acorn 语法校验:在进入 vm2 前用 acorn 做一次 parse,避免明显语法错误在沙箱里报错不明确或卡死。
- runInSandbox(code):调用沙箱模块执行代码;若为 HTTP 服务,在返回内容前加上
SANDBOX_HTTP_SERVICE_PREFIX,命令层检测到后挂起进程。
7.6 沙箱相关提示词:为什么要这么写
沙箱功能里用到两套提示词:一套在命令层做调度(选 sandbox 还是 direct_answer),一套在沙箱工具内部做代码生成(只生成可在沙箱中执行的 JavaScript)。两套职责分离,便于单独调优。下面分别贴出关键内容,并说明为什么要这么写。对应代码位置:src/bin/command/agentCommand/sandbox.ts(调度)、src/bin/langchain/sandbox/prompt.ts(沙箱环境说明)、src/bin/langchain/tools/sandbox.ts(代码生成规则拼接)。
7.6.1 调度提示词(DISPATCHER_SYSTEM_PROMPT)
完整内容(sandbox.ts 命令入口):
你是调度助手:根据用户输入决定「要不要执行代码」,并只调用一个工具。
规则:
1. **需要执行代码/操作文件时** → 调用 `sandbox`,把用户的整句指令原样传入。例如:创建/修改/删除文件、生成 HTML、批量重命名、列目录、运行命令等。
2. **纯问答、不需要动文件或跑代码时** → 调用 `direct_answer`,用 `answer` 参数给出简短回答(1~3 句话,不要长篇大论)。
3. 只调用一个工具,不要同时调用两个。不要输出过长文本。
为什么要这么写:
| 部分 | 作用 | 不这么写的后果 |
|---|---|---|
| 角色「你是调度助手」 | 让模型只做「二选一」决策,不越权去解释或生成代码 | 模型可能既调工具又自己啰嗦一大段,或去「猜」用户意图时输出长文 |
| 任务「根据用户输入决定要不要执行代码,并只调用一个工具」 | 明确输出形态:只产生一次 tool_calls,且只选一个工具 | 可能同时调 sandbox 和 direct_answer,下游难以处理;或多次调用增加延迟 |
| 规则 1「需要执行代码/操作文件时 → 调用 sandbox,整句指令原样传入」 | 与 Tool 的 name: "sandbox" 一致;举例(创建/修改/删除文件、生成 HTML、批量重命名等)帮助模型判断「何时算需要动文件」 | 模型容易在纯问答时也调 sandbox,或把指令改写成自己的话导致语义漂移 |
| 规则 2「纯问答时 → 调用 direct_answer,answer 参数 1~3 句话」 | 与 Tool 的 name: "direct_answer" 和 schema 里的 answer 一致;约束长度便于终端展示 | 纯问答时模型可能调 sandbox 或输出过长,影响体验和 token |
| 规则 3「只调用一个工具,不要输出过长文本」 | 强化「只选一个」和「不附带长文」,避免模型在 tool_calls 之外再输出大段说明 | 容易出现「调了工具又输出好几段话」或一次多个 tool_calls |
总结:调度提示词的核心是角色单一(调度)、任务清晰(二选一)、规则与 Tool 的 name/schema 一一对应,这样模型才会稳定地「只选一个工具、传对参数」。
7.6.2 沙箱环境说明(prompt.ts:SANDBOX_SCHEMA / getSandboxPromptMarkdown)
作用:在沙箱工具内部,把「沙箱里有哪些全局对象/函数、怎么用」写成 Markdown(或 JSON),通过 getSandboxPromptContext("markdown") 拼进 SANDBOX_SYSTEM_PROMPT 的前半部分,让生成代码的那次模型只使用这些 API,不写 require('fs')、require('path') 等(沙箱里没有原生 require)。
为什么要这么写:
- 按类别分块(Node 内置、异步、Web 框架、子进程、便捷 API):模型按「要找什么能力」快速定位,减少幻觉(例如去用未暴露的 API)。
- 写清默认操作目录「默认使用当前命令行所在目录(即 __workspace);路径用相对路径」:避免模型生成绝对路径或假设别的 cwd,导致执行时报「文件不存在」。
- 便捷 API 用表格列出(createFile、readFile、listDir、rename、remove 等):表格比大段文字更利于模型「按名选用」,且与
common.ts里真实暴露的函数一致;对易错点(如「改文件名时用 rename,不要只 createFile 新路径」)单独写一句,减少同一内容两份文件。 - 启动服务、修改文件名等单独强调:因为模型常犯「只生成文件不 listen」或「只 createFile 新路径不删旧文件」的错,所以在环境说明里就约束好,比只在后面「要求」里写更醒目。
对应代码:src/bin/langchain/sandbox/prompt.ts 中的 SANDBOX_SCHEMA(JSON 化配置)、getSandboxPromptMarkdown()(生成给模型看的 Markdown);工具里用 getSandboxPromptContext("markdown") 取这段,再拼上下面的「要求」部分。
7.6.3 沙箱代码生成规则(SANDBOX_SYSTEM_PROMPT 后半部分)
在「沙箱环境说明」之后,工具里拼接的要求(src/bin/langchain/tools/sandbox.ts 中的 SANDBOX_SYSTEM_PROMPT)如下,并说明每条为什么要这么写:
---
请根据用户的自然语言指令,生成一段可在上述沙箱中执行的 JavaScript 代码。
要求:
1. 只输出代码,不要解释或 markdown 标题。
2. 代码中只能使用上文列出的全局对象和函数。
3. 若需要返回结果给用户,请用 return 或 console.log。
4. 可以包在 ```js ... ``` 里,也可以直接输出裸代码。
5. 如果你认为执行后有重大错误请直接返回 "执行失败"。
6. **默认操作目录**:如果用户没有指定在哪个目录操作,默认使用当前命令行所在目录(即 __workspace);路径用相对路径如 '.' 或 '文件名' 即可。
7. **启动服务型项目时**:尽量在沙箱内完成,单段代码中完成应用创建、路由、app.listen 等,不要只生成文件让用户自己运行或依赖沙箱外的步骤;用 app.listen(port, () => console.log('http://localhost:' + port)) 打印地址,代码末尾不要 return。
8. **若本次生成的代码会启动 HTTP 服务**(如 Koa/Express 的 app.listen),请在代码块后单独一行写 __IS_HTTP_SERVICE__,以便宿主进程挂起(用户 Ctrl+C 停止)。
9. **修改文件名或格式时**:用 rename(oldPath, newPath) 重命名,或先 readFile 再 createFile 新路径后 remove 原文件;不要只 createFile 新路径而保留原文件,避免同一内容有两份。
为什么要这么写:
| 条 | 目的 | 不这么写的后果 |
|---|---|---|
| 1 只输出代码,不要解释或 markdown 标题 | 便于从回复里稳定解析出「一段代码」;解析逻辑依赖「要么 ```js 块要么裸代码」 | 模型输出大段说明 + 代码,解析容易取错或取到解释文本 |
| 2 只能使用上文列出的全局对象和函数 | 与 prompt 前半部分「沙箱环境说明」一致,防止用 require('fs') 等沙箱内不存在的东西 | 生成的代码在 vm2 里报 require is not defined 或访问未暴露 API 报错 |
| 3 返回结果用 return 或 console.log | 宿主通过 IIFE 的返回值或 stdout 拿结果;明确两种出口,模型不会只写中间变量不输出 | 用户看不到执行结果,或解析不到返回值 |
| 4 可以包在 ```js 里也可以裸代码 | 解析时两种都支持(parseCodeFromResponse),给模型容错空间 | 若强制只接受一种,模型有时会选另一种导致解析失败 |
| 5 认为有重大错误时直接返回 "执行失败" | 避免模型硬生成明显会报错的代码,让工具层直接返回可读提示 | 容易得到一段必然报错的代码,用户体验差 |
| 6 默认操作目录 __workspace,路径用相对路径 | 与 prompt 前半部分一致;和 common.ts 里 createSandbox 的 root 对齐 | 模型生成 /tmp/xxx 或其它绝对路径,在沙箱里路径不对 |
| 7 启动服务时在沙箱内完成 listen,不要只生成文件 | 用户说「起一个 Koa 服务」时期望直接能访问,而不是再手动运行 | 只生成 app.js 让用户自己 node app.js,不符合「一条指令完成」的预期 |
| 8 HTTP 服务时在代码块后写 IS_HTTP_SERVICE | 工具和命令层用该标记判断是否挂起进程(不退出),否则服务会立刻退出 | 启动的服务一启动就退出,用户无法访问 |
| 9 改文件名用 rename 或 读→写新→删旧 | 与环境说明里「不要只 createFile 新路径」一致,避免同一内容两份文件 | 用户说「把 a.txt 改成 b.txt」时生成两个文件,语义错误 |
总结:前半部分(prompt.ts)负责能力边界与用法约定,后半部分(工具里拼接)负责输出格式、默认目录、HTTP 服务、重命名等易错约束;两段合在一起,模型才能稳定生成「可解析、可执行、行为符合预期」的沙箱代码。
7.7 沙箱环境与执行引擎
- 环境定义(
src/bin/langchain/sandbox/common.ts):createSandbox(workspaceRoot) 返回一个对象,包含 vm2 所需的 sandbox 全局变量——如__workspace、fs/path/process/os/Buffer/util/console/URL、Promise/setTimeout、Koa/koaRouter、child_process.execSync/spawnSync,以及便捷方法 createFile / readFile / listDir / rename / remove / copy / move / stat / listFilesRecursive / globFiles / requireFromWorkspace 等。路径未指定时默认为当前命令行所在目录(即__workspace)。 - 执行(
src/bin/langchain/sandbox/index.ts):使用 vm2 的VM,把上述 sandbox 对象传入;为支持「顶层 return」,将用户代码包成 IIFE 再执行:
const wrapped = `(function() {\n${code}\n})()`;
const result = vm.run(wrapped);
return result instanceof Promise ? await result : result;
这样生成的代码里可以直接 return ...,返回值会交给命令层展示;若 return 的是 Promise,会 await 后再返回。
- 提示词与 API 说明(
src/bin/langchain/sandbox/prompt.ts):SANDBOX_SCHEMA 描述沙箱内所有全局对象和函数的类型、参数、示例;getSandboxPromptMarkdown() 将其转成 Markdown 表格和列表,注入到SANDBOX_SYSTEM_PROMPT,使模型只使用这些 API 生成代码,避免使用未暴露的 Node 或浏览器 API。
7.8 小结
| 模块 | 作用 |
|---|---|
| sandbox 命令 | 解析 st sandbox <指令>,用调度 Agent + bindTools 在 sandbox / direct_answer 间选择,并循环处理 tool_calls,直到模型不再调用工具;检测 HTTP 服务标记后挂起进程。 |
| sandboxTool | 根据用户指令调用模型生成沙箱代码 → Acorn 校验 → runInSandbox 执行 → 将结果或错误以 ToolMessage 形式返回。 |
| answerTool | 纯问答时由模型填入 answer,原样返回给用户。 |
| createSandbox / runInSandbox | 提供 vm2 沙箱全局环境(含 Node 与便捷文件 API),IIFE 包裹执行并支持 return/Promise。 |
| prompt 与 SANDBOX_SCHEMA | 把沙箱能力描述成 Markdown/JSON,约束模型只生成合规、可执行的代码。 |
整体上,这就是一个「自然语言 → 调度 Agent(Tool 二选一)→ 沙箱工具内再调模型生成代码 → 语法校验 → vm2 执行 → 结果回传」的闭环,用到的 LangChain 概念包括 Tool、bindTools、SystemMessage/HumanMessage/AIMessage/ToolMessage、model.invoke,对应官网 Tools 与 Messages 的用法。
八、提示词工程:如何写好提示词
前面提到的编排、RAG、沙箱等,最终都要通过「和模型说清楚要做什么」才能生效,这部分就是提示词工程(Prompt Engineering)。下面用通俗方式说明其重要性,并给出一套可落地的书写原则,便于在业务里统一规范、减少无效调用。
8.1 为什么提示词重要
模型本身不会「主动知道」业务规则、输出格式或边界条件,这些都需要通过**输入文本(提示词)**显式告诉它。提示词写得好,模型更容易:
- 做对事:理解任务意图、约束和优先级,减少答非所问或越权行为。
- 出对格式:便于下游解析(如 JSON、表格、代码块),减少二次清洗。
- 控制成本与延迟:约束长度、禁止冗长解释,有利于 token 与响应时间可控。
因此,提示词是连接「业务需求」和「模型能力」的接口;写好提示词,是落地 AI 功能时性价比很高的投入。
8.2 如何写好提示词:几条可操作原则
归纳为角色、任务、约束、格式、示例五类要素,按需组合即可。
| 要素 | 说明 | 示例(一句话) |
|---|---|---|
| 角色 | 让模型进入「谁在说话」的设定,行为更一致 | 「你是调度助手」「你是只生成代码的沙箱执行器」 |
| 任务 | 用一句话说清「要干什么」,避免模糊 | 「根据用户输入决定调用 sandbox 还是 direct_answer」「生成可在沙箱中执行的 JavaScript」 |
| 约束 | 明确「不能做什么」「必须怎么做」,减少越界 | 「只输出代码,不要解释」「只能使用上文列出的全局对象」「回答控制在 1~3 句话」 |
| 格式 | 规定输出形态,方便解析与展示 | 「返回 JSON」「用```js ... ``` 包住代码」「若启动 HTTP 服务请在代码块后写 IS_HTTP_SERVICE」 |
| 示例 | 给 1~2 个输入输出样例,大幅提升格式与风格一致性 | 「输入:生成 index.html → 输出:仅一段可执行代码」 |
书写习惯建议:
- 先写「角色 + 任务」,再补约束和格式,最后需要时加示例。
- 一条提示词只服务一个目标:调度就只做调度,生成代码就只生成代码,避免混在一起导致模型「不知道该优先听哪句」。
- 关键规则用加粗或编号,便于模型注意(如「只调用一个工具」「3. 只输出代码」)。
- 迭代优化:用真实用例跑几轮,看模型常犯的错误(漏约束、格式乱、话太多),再回头改提示词补一句、减一句。
8.3 本文中的提示词实践(对应关系)
- 调度提示词(七、沙箱插件)角色:调度助手。任务:根据用户输入决定调用
sandbox还是direct_answer。约束:只调用一个工具、不要长篇大论。这样模型就不会既调工具又自己啰嗦一大段。 - 沙箱代码生成提示词****角色:沙箱内代码生成器。任务:根据用户指令生成可在给定沙箱中执行的 JavaScript。约束:只使用列出的 API、默认目录为
__workspace、启动服务时标注__IS_HTTP_SERVICE__。格式:可包在 ```js ... ``` 里或裸代码。示例:通过 SANDBOX_SCHEMA / Markdown 表格把「有哪些函数、怎么用」写清楚,等于给了结构化示例。 - 温度(二、认识模型) 温度虽不是「一句话提示词」,但属于同一类控制:通过参数告诉模型「要更确定还是更发散」。代码/结构化输出用低温度,创意类用稍高温度,本质上也是在「写好」对模型的行为约束。
8.4 参照:业务中使用的提示词示例
下面摘录并整理业务里实际用过的提示词,作为「角色 + 任务 + 约束 + 格式 + 示例」的参照,便于对照前文原则做迭代。
示例一:生成管理后台页面的 Prompt(低代码 / 运营者模块)
角色/任务:让 AI 在「30% 框架内」生成管理后台页面代码,而非凭空创新;需求边界、数据格式、交互范式由人工先锁定。
约束与格式(节选):
- 1.1 顶部导航栏:用 el-menu,背景色 #409EFF,文字白色,选中时背景加深 10%;左侧预留项目名称插槽(slot="brand");中间菜单项通过数组 NavItems 注入,结构
NavItem { name, route, icon? };暴露事件 @select、@menu-click。Store 的 module 划分、state 形状、mutation 名由人工先锁定,AI 只生成具体 CRUD 逻辑。 - 1.2 左侧列表区块:点击高亮用 class 切换(.is-active);中间内容区 flex:1 自适应。
- 1.3 左上角按钮组:添加按钮 el-button + Plus 图标、文字「新增」;搜索框 el-input + Search 图标,v-model 绑定 keyword,触发 @search。
- 1.4 列表实现:字段校对由人工完成;AI 直接生成固定列数的 el-table,给出
<el-table-column>骨架,prop 与后端字段保持一致。 - 1.5 封装 ListTable 组件:外部传入 columns:
{ key, label, width?, slot? }[];内部维护 rendererMap,按 column.key 映射渲染函数;插槽命名规则table-[key],如<template #table-status>。
要点:把「要生成什么、用什么组件、数据结构长什么样」写清楚,模型在给定框架内填代码,便于后续人工校对和联调。
示例二:AI 提升学习能力(设计模式 + 注释 + 单测)
角色/任务:用 AI 把「查文档 + 写样板」的时间省下来,在较短时间内给出「带设计模式 + 注释 + 单测模板」的高可维护代码。
约束:先指定设计模式(如 Strategy、Factory、Observer);要求 AI 生成 TypeScript 实现,并逐行补充 JSDoc 与单测用例;对存量代码,可让 AI 按相同模式做渐进式重构,人工只做 Code Review。
示例三:LangChain 调研结论(Function Calling / Multi-Agent / MCP)
- Function Calling:本地预注册函数,LLM 仅返回 JSON 参数;本地框架负责反射调用。LLM 本身不拥有、也不执行函数——它只是「点名 + 传参」。
- Multi-Agent 协作:同一进程内可启多个 Agent 实例,每个实例 system prompt 只聚焦单一职责(产品、开发、测试);通过消息队列顺序传递上下文,降低单 Agent 的上下文长度与幻觉概率。
- MCP(Model Context Protocol):统一「工具描述 + 调用」协议,Agent 通过 MCP 把工具清单发给 LLM,LLM 按 MCP 格式返回调用指令,本地 SDK 再执行真正的 Function Calling。类比:Agent 是顾客,MCP 是菜单 + 点单协议,Function Calling 是后厨实际炒菜。
示例四:智能汇总 diff 生成 commit(工作流描述)
整体流程(一页讲解用):获取 diff 信息 → 使用 LangChain 的 TokenTextSplitter 将文本切分为约 1500 大小的块 → Agent 对片段并发处理、AI 总结 → 将每个片段的结果再喂给 AI,生成 JSON(generalize 描述文本、commitMsg 标准化 commit 信息)→ 命令行确认后提交。
分步要点:
- 使用 git 获取 diff 信息。
- 使用 LangChain 的 TokenTextSplitter 将文本切分为约 1500 大小的模块。为什么要切分:一次数据量过大,直接丢给 Agent 生成速度慢;切分为 chunk 后通过 Promise.all 并发请求,减少等待时间。为什么不选 RAG/向量库:仅对 diff 做一次性汇总,先存向量库再检索过重,不适合。
- 用提示词让 AI 对非代码片段做文字性总结,对代码片段读取函数名并生成函数简述,收集成数组。
- 将多个片段汇总后的结果再作为提示词传入 AI,数据量小且能通过类型区分「代码」与「描述性文本」。
- 让 AI 用该数组生成一个 JSON:
generalize为描述整体的数组(展示为详细项),commitMsg为标准化 commit 结果;后续用函数确认并调用 git 提交。
以上示例可作为撰写「角色、任务、约束、格式、示例」时的参照,按业务场景裁剪即可。
8.5 小结
提示词工程就是把「要模型做什么、不能做什么、输出长什么样」说清楚;用好角色、任务、约束、格式、示例五类要素,并在实际用例上小步迭代,就能在少改代码的前提下,明显提升模型输出的可用性和稳定性。我们在调度、沙箱、RAG 等环节都已经按这套思路在写提示词,后续新功能也可以沿用同一套规范。