从 0 到 1 构建 AI 助手

综合 Prompt、RAG、Tool Calling,手把手搭建一个可运行的 AI 助手:系统设计、技术栈、代码结构、常见坑

19 min read Part of AI Foundation · Ch. 11

从 0 到 1 构建 AI 助手

flowchart LR
  A["从 0 到 1 构建 AI 助手"]
  A --> B["分类:基础概念"]
  A --> C["关键词:AI"]
  A --> D["关键词:实战"]
  A --> E["关键词:RAG"]
  A --> F["关键词:Tool Calling"]

这是 Foundation 系列的收官之作。前面讲过的 Prompt、RAG、Embedding、向量数据库、Tool Calling、系统架构,到这里终于要真正拼起来:不是再理解一个概念,而是把它们组装成一个能跑、能调、能扩展的 AI 助手原型。


这篇文章会讲什么

前面十篇文章解决的是“理解问题”:

  • 模型为什么能工作
  • Prompt 为什么重要
  • RAG 为什么需要 Embedding 和向量数据库
  • Tool Calling 为什么能让模型获得外部能力
  • AI 应用为什么一定会长出编排层和多层架构

但现实里,“知道这些概念”和“把产品做出来”之间,还有一道非常典型的鸿沟:

你知道每个零件是干什么的,但还不知道这些零件应该按什么顺序接起来。

真正的 AI 应用开发,难点往往不在某一个单点技术,而在“拼装”:

  • Prompt 放哪一层维护?
  • RAG 是每次都检索,还是只在部分意图上检索?
  • 工具调用和知识库问答怎么共存?
  • 多轮对话的历史、摘要、状态分别放哪?
  • 什么时候直接回答,什么时候应该查知识库,什么时候必须调用工具?
  • 如果检索失败、工具失败、模型胡说,系统应该怎么降级?

这篇文章的目标,就是把这些碎片真正拼成一个最小可用系统。

它不会给你一份“复制粘贴即生产可用”的完整代码库,因为真实项目的业务差异太大;但它会给你一张足够清晰的蓝图,让你知道:

  • 最小可行的 AI 助手应该长什么样
  • 每个模块负责什么
  • 技术栈怎么选
  • 代码结构怎么拆
  • 最容易踩的坑在哪
  • 什么东西应该先做,什么东西可以后补

实战资源

  • LangChain 官方 Quickstart 现在已经把“从简单设置到可运行 agent”作为入门路径之一,适合快速验证流程。:contentReference[oaicite:0]{index=0}
  • Vercel 的 AI SDK 明确定位为帮助开发者在 Next.js、Vue、Svelte、Node.js 等环境中快速构建 AI 应用,并抽象不同模型提供商之间的差异。:contentReference[oaicite:1]{index=1}
  • OpenAI 的 GPT-4.1 mini 官方模型页把它描述为更小、更快、低延迟、支持长上下文和工具调用的模型,适合很多应用场景中的性价比路线。:contentReference[oaicite:2]{index=2}
  • Anthropic 当前公开主推的 Sonnet 系列已更新到 Claude Sonnet 4.6,并明确面向开发者提供 API 与 agent 场景支持。:contentReference[oaicite:3]{index=3}

先说结论:先做一个“够用的助手”,不要一开始就做“全能 Agent”

很多人第一次做 AI 助手时,脑中默认的目标会不自觉膨胀成:

  • 能聊天
  • 能查公司知识库
  • 能发邮件
  • 能查数据库
  • 能自动调十几个内部系统
  • 能自己规划任务
  • 能持续记住用户
  • 能像员工一样工作

这当然很诱人,但从落地角度看,最稳妥的路线通常不是:

一开始就做一个“什么都能干”的 Agent

而是先做一个:

边界清楚、链路短、可调试的 AI 助手原型

这类原型最适合具备三种能力:

  1. 基础对话能力:能稳定回答普通问题
  2. 知识库问答能力:能回答企业内部文档里的内容
  3. 少量明确工具能力:例如查天气、做计算、查某个固定业务接口

这三类能力组合起来,已经足够把 Foundation 系列前面的核心知识串起来,而且工程复杂度还在可控范围内。

所以,本文构建的不是一个“万能 Agent”,而是一个最小可用的、可扩展的 AI 助手底座


1. 我们要构建什么

先看定义:一个支持多轮对话、知识库问答和少量工具调用的 AI 助手原型,它能够在“直接回答 / 检索知识 / 调用工具”三种路径之间切换。


最小目标,而不是最大目标

这个原型我们只做四件事:

能力作用实现方式
通用对话处理普通问题、寒暄、简单说明System Prompt + 对话历史
知识库问答回答企业内部文档、制度、FAQRAG:检索后注入上下文
天气查询处理实时信息Tool: get_weather(city)
数学计算处理确定性计算Tool: calculator(expression)

这个能力集合非常有代表性,因为它覆盖了三条最核心的 AI 应用路径:

1. 直接生成路径

模型只靠上下文和已有知识回答。

2. 检索增强路径

模型先拿文档证据,再回答。

3. 工具调用路径

模型先请求外部能力,再根据结果回答。

一旦你把这三条路径做通,后续无论要加:

  • 工单系统
  • 邮件发送
  • 日历管理
  • 用户画像
  • 更复杂的业务 API

本质上都是在已有架构上继续扩展,而不是推倒重来。


这个助手的一轮对话可能怎么走

例如:

用户:公司年假政策是什么?
→ 系统判断:这是知识问题
→ 检索员工手册相关片段
→ 模型基于检索结果回答
用户:北京今天多少度?
→ 系统判断:这是实时信息
→ 模型调用 get_weather("北京")
→ 应用执行天气工具
→ 模型基于工具结果回答
用户:那如果加 10 度呢?
→ 系统判断:依赖上一轮结果且需要确定性计算
→ 模型调用 calculator("25+10")
→ 应用执行计算器
→ 模型生成最终答案

这三个例子正好对应三种典型流:

  • 纯语言回答
  • RAG
  • Tool Calling

而这已经足够构成一个“真正像产品”的 AI 助手。


2. Step 1:先设计一个靠谱的 System Prompt

先看定义:System Prompt 的职责不是“把所有知识都塞进去”,而是定义这个助手是谁、会什么、不会什么、遇到什么情况该走哪条路径。


System Prompt 的定位一定要清楚

很多初学者会在 System Prompt 里做两件容易出问题的事:

1. 把它写成知识库

试图把大量企业规则、FAQ、说明文档全部塞进去。

2. 把它写成万能规则墙

一条条加限制,最后 system prompt 长得像一部操作手册。

更稳妥的思路是:

System Prompt 负责角色、原则、边界,不负责承载全部知识。

知识应该尽量走 RAG;
实时信息和动作应该尽量走工具;
System Prompt 更适合定义这个助手的“行为框架”。


一个好 System Prompt 至少要覆盖四件事

1. 角色

告诉模型它是谁。

例如:

  • 你是公司内部智能助手
  • 你负责回答制度、流程和常见问题
  • 你也可以调用天气和计算工具

2. 能力边界

告诉模型哪些能力是它有的,哪些能力必须借助工具或知识库。

3. 失败策略

如果知识库没有答案怎么办?
如果工具不可用怎么办?
如果信息不足怎么办?

4. 输出风格

例如是否简洁、是否分点、是否在引用知识库时注明来源。


一个足够实用的 System Prompt 骨架

下面是一个正文级、而不是玩具级的示意:

你是 XX 公司的智能助手。

你的职责:
1. 回答公司知识库中的制度、流程和常见问题
2. 查询实时天气(必须通过 get_weather 工具)
3. 进行数学计算(必须通过 calculator 工具)

回答规则:
- 对公司内部知识问题,优先依据提供的参考资料回答
- 如果参考资料不足,不要编造,明确说明“当前资料不足,我无法确认”
- 对实时天气问题,必须调用天气工具,不要猜测
- 对计算问题,优先调用计算工具,不要心算复杂表达式
- 回答风格简洁、清晰;必要时分点
- 如果引用知识库内容,尽量指出来源文档名称

这类 Prompt 的价值在于:
它不是只写“你是一个有帮助的助手”,而是已经把助手的三条主路径写进去了:

  • 什么时候用知识
  • 什么时候用工具
  • 什么时候不要乱猜

System Prompt 不要承担的内容

不要把这些东西硬塞进 system:

  • 大量 FAQ 正文
  • 经常更新的业务信息
  • 超长 few-shot
  • 大量用户历史
  • 大片检索结果

这些信息的更新频率高、与当前问题强相关、且 token 成本高,更适合放在动态上下文里,而不是 system prompt 里。

先看定义:

System Prompt 管“行为逻辑”,Context 管“当前信息”。


3. Step 2:接入知识库(RAG)

先看定义:RAG 的目标不是“让模型记住所有文档”,而是在用户提问时,把最相关的那几段资料动态拿回来,注入当前上下文。


RAG 在这个系统里的角色

这个助手之所以不是普通聊天机器人,关键就在于:

它不能只靠模型参数回答问题,而要能回答“你公司自己的东西”。

例如:

  • 年假政策
  • 报销流程
  • 内部工具说明
  • 员工手册
  • 客服 SOP
  • 项目文档

这些内容:

  • 模型训练时未必见过
  • 即使见过也未必是你公司的最新版本
  • 不能只靠“模糊记忆”回答
  • 通常需要来源依据

这就是 RAG 的价值所在。


典型 RAG 流程

一个最小可用的知识库接入流程通常长这样:

文档 → 清洗 → 切片 → Embedding → 向量入库

查询时:

用户问题 → Embedding → 向量检索 → Top-K 文档片段 → 注入 Prompt → 模型回答

这条链路听起来简单,但真正影响效果的往往不是“有没有向量库”,而是中间几个细节。


文档接入的四个关键步骤

1. 文档加载

先把 PDF、Word、网页、Markdown、数据库记录等转成可处理文本。

2. 文本清洗

清掉目录、页眉页脚、噪声字符、重复段落、空白行等。

3. 切片(Chunking)

把长文切成适合检索的片段,而不是整篇全文塞进去。

4. Embedding + 入库

把每个片段向量化,并连同 metadata 一起存入向量库。

这里 metadata 至少建议带:

  • source:来源文档
  • title:标题
  • section:章节
  • doc_type:文档类型
  • tenant_id:租户或知识空间(如需要)

因为后面做过滤、引用展示、结果解释时都会用到。


Chunking 为什么是第一大坑

第一次做 RAG,最容易低估的就是 chunking。

切太大

会导致一个 chunk 里塞了太多主题,检索不精准;模型拿到后也不容易抓住重点。

切太小

上下文会碎掉,检索回来的片段缺少必要语义,模型可能看不懂前因后果。

完全不重叠

边界信息容易断裂。

所以一个更稳妥的起步方案通常是:

  • 固定长度切片
  • 保留适度 overlap
  • 再根据文档类型逐步优化

例如:

  • 500 token 左右一个 chunk
  • 50–100 token overlap

这不是绝对标准,但足够作为原型起点。


Top-K 为什么不要贪多

很多人觉得:

检索越多越保险。

但在实际 RAG 里,Top-K 太大往往会带来副作用:

  • 无关内容增多
  • prompt 变长
  • token 成本上升
  • 重点被稀释
  • 模型更难聚焦

所以原型阶段,一个很实用的默认值往往是:

  • Top-K = 3 到 5

不够再慢慢调,而不是一开始就塞 20 条。


一个最小 RAG 伪代码

def retrieve_context(user_question: str) -> str:
    query_vec = embed(user_question)
    docs = vector_db.search(query_vec, top_k=5)
    return "\n\n".join(
        f"[来源: {d.metadata['title']}]\n{d.content}"
        for d in docs
    )

然后在组装消息时,把它放进上下文:

context = retrieve_context(user_question)

user_prompt = f"""
请优先基于以下参考资料回答:

{context}

用户问题:
{user_question}
"""

这就是最小可用的 RAG 形态。


4. Step 3:添加 Tool Calling

先看定义:工具调用不是“让模型自己去做事”,而是让模型先输出结构化调用意图,再由应用执行工具、回填结果、继续对话。


为什么在这个原型里只加两个工具

为了把重点放在架构和闭环,而不是工具数量,我们只加两个最典型的工具:

  1. get_weather(city)
  2. calculator(expr)

它们分别代表两类非常常见的工具:

  • 实时信息查询工具
  • 确定性计算工具

一旦这两类都跑通,你以后再加:

  • search_docs
  • get_user_order
  • create_ticket
  • send_email

本质上只是复用同一套工具调用框架。


工具定义示意

tools = [
    {
        "type": "function",
        "function": {
            "name": "get_weather",
            "description": "获取指定城市当前天气,返回温度和天气状况",
            "parameters": {
                "type": "object",
                "properties": {
                    "city": {"type": "string", "description": "城市名称"}
                },
                "required": ["city"]
            }
        }
    },
    {
        "type": "function",
        "function": {
            "name": "calculator",
            "description": "计算数学表达式,如 1+2*3",
            "parameters": {
                "type": "object",
                "properties": {
                    "expr": {"type": "string", "description": "数学表达式"}
                },
                "required": ["expr"]
            }
        }
    }
]

注意这里最重要的不是语法,而是两个原则:

1. 工具要语义清楚

工具应该像业务动作,不要太宽泛。

2. 参数要尽量明确

description、required、格式要求都要写清楚。


工具执行循环怎么写

一个最小的 Tool Loop 往往长这样:

messages = [system_msg, *history, user_msg]

while True:
    response = model.chat(messages, tools=tools)

    if not response.tool_calls:
        return response.content

    for tc in response.tool_calls:
        result = execute_tool(tc.name, tc.arguments)
        messages.append(tool_result_message(tc.id, result))

这个循环背后的思想非常关键:

模型不只是回答一次,而是在“调用工具 → 读结果 → 再决定”的循环里工作。

这就是 Agent 雏形。


工具层必须做的三件事

1. 参数校验

模型给的参数不能直接信任,必须过 schema 校验。

2. 权限注入

如果工具会访问用户或租户数据,不要让模型自己决定 user_id、tenant_id,而要由后端注入。

3. 错误处理

工具失败时要能返回可控错误,而不是直接把异常栈抛给用户。

例如:

def execute_tool(name, args):
    if name == "calculator":
        return safe_calculate(args["expr"])
    elif name == "get_weather":
        return weather_client.get(args["city"])
    else:
        raise ValueError("Unknown tool")

原型阶段可以简单,但安全边界不能没有。


5. Step 4:把 RAG 和 Tool Calling 放进同一条编排链里

先看定义:真正的助手不是“有 RAG”或“有工具”二选一,而是要在同一轮请求里决定:现在应该直接回答、先检索,还是先调用工具。


三条路径要怎么共存

这是从 Demo 到助手原型的关键一步。

一个简单但实用的思路是:

默认先看当前问题类型

  • 如果像知识库问题:优先做 RAG
  • 如果像天气或计算问题:允许工具优先介入
  • 如果只是简单寒暄或普通问答:直接回答

最终仍由模型统一生成回答

这意味着,RAG 和工具都不是最终输出层,而是“给模型补信息的中间层”。


一个可行的简化编排逻辑

原型阶段,你可以采用非常朴素的策略:

  1. 先用规则判断是否是明显工具型问题
  2. 如果不是,再做知识库检索
  3. 把检索结果和工具定义一起交给模型
  4. 让模型决定是否进一步调用工具

这样做的好处是:

  • 避免所有请求都盲目检索
  • 检索内容和工具能力可以并存
  • 保留一定灵活性

一个主流程伪代码

def handle(user_msg, history):
    context = ""

    if looks_like_knowledge_question(user_msg):
        docs = retriever.search(user_msg, top_k=5)
        context = format_docs(docs)

    messages = build_messages(
        system_prompt=SYSTEM_PROMPT,
        context=context,
        history=history,
        user_msg=user_msg
    )

    while True:
        response = model.chat(messages, tools=tools)

        if not response.tool_calls:
            return response.content

        for tc in response.tool_calls:
            result = execute_tool(tc.name, tc.arguments)
            messages.append(tool_result_message(tc.id, result))

这已经是一条非常典型的“小型 AI 编排链”了。


6. Step 5:构建 UI,不只是“有个输入框”

先看定义:AI 助手的用户体验,很大一部分不取决于模型本身,而取决于 UI 是否能把“等待、检索、工具调用、引用来源、失败状态”表达清楚。


一个最小可行 Chat UI 至少需要什么

1. 消息列表

显示用户和助手消息。

2. 输入框

支持回车发送、多行输入。

3. 流式输出

让用户边等边看到生成内容,而不是卡住几秒。

Vercel 的 AI SDK 官方文档明确把流式输出当作一等能力来支持。:contentReference[oaicite:4]{index=4}

4. 工具状态提示

例如:

  • 正在查询天气…
  • 正在检索知识库…
  • 正在计算…

这类中间状态会显著降低“系统没反应”的感觉。

5. 引用来源展示

如果回答来自知识库,最好展示来源文档名或相关片段。


为什么流式展示几乎是标配

对用户来说,AI 应用最糟糕的体验之一就是:

点发送后,界面静止三秒到十秒,什么都看不到。

而流式输出可以把等待感拆散。
即使总耗时没变,用户主观体验也会更好。

所以,如果你的助手是聊天型产品,流式展示通常不是“锦上添花”,而是接近默认配置。


UI 层还要不要显示工具调用过程

建议至少在原型阶段显示。

原因有三个:

  1. 帮助调试
    你能看出来模型到底有没有调用工具、调用了几个。

  2. 帮助建立用户信任
    用户能理解“这次回答为什么慢一点”或“为什么结果更可靠”。

  3. 帮助后续做可观测性设计
    以后你会很自然地把这些状态延伸到日志、监控和 traces 里。


7. 技术栈推荐:先以“能跑通闭环”为目标

先看定义:原型阶段最重要的不是“最先进”,而是“最快把整条链路跑通”。语言、框架、模型和向量库都应该服从这个目标。


一套非常稳的原型栈

后端语言

Python 或 Node.js 都可以。

  • Python 的优势是 AI 生态完整、样例多
  • Node 的优势是前后端统一、适合全栈团队

编排框架

  • 想快速验证:LangChain / LlamaIndex 都可以
  • 想保持强可控:直接自研轻量 orchestration 也完全可行

LangChain 官方 quickstart 现在已经明确把“快速搭建 agent”作为起步路径。:contentReference[oaicite:5]{index=5}

模型

一个非常实用的思路是:

  • 普通助手场景:优先低延迟、支持工具调用的模型
  • 难推理场景:再换更强模型

OpenAI 官方文档把 GPT-4.1 mini 描述为更快、低延迟、支持 1M 上下文和工具调用的模型;Anthropic 当前面向开发者公开主推的 Sonnet 系列则是 Claude Sonnet 4.6。:contentReference[oaicite:6]{index=6}

Embedding

起步阶段,优先选:

  • API 简单
  • 检索效果稳定
  • 生态成熟

向量库

  • 本地原型:Chroma / pgvector 都可以
  • 云上原型或更稳部署:Qdrant、Pinecone 一类方案更常见

前端

React + Vercel AI SDK 是一条很顺的路线,因为它天然支持流式 UI 和模型抽象。:contentReference[oaicite:7]{index=7}


一个更重要的选型原则

不要问:

“2026 最强栈是什么?”

更应该问:

“哪套技术栈能让我在一周内把完整闭环跑通,并且两周后还愿意继续维护?”

原型阶段最怕的不是技术不够先进,而是:

  • 一上来引入太多组件
  • 复杂度先于需求增长
  • 花很多时间在基础设施,而不是验证产品闭环

8. 代码结构怎么拆:不要把所有逻辑塞进一个 chat.py

先看定义:AI 助手一旦同时具备 Prompt、RAG、Tool Calling,多半就已经不适合写成一个文件。按职责拆模块,会极大降低后面扩展和排错的成本。


一个足够健康的目录结构示意

project/
├── api/
│   └── chat.py              # HTTP 入口
├── orchestration/
│   └── assistant.py         # 主流程:RAG + Tool Loop + 多轮
├── prompt/
│   └── system_prompt.txt    # System Prompt 模板
├── rag/
│   ├── retriever.py         # 向量检索
│   ├── ingest.py            # 文档导入 / chunk / embedding
│   └── formatter.py         # 检索结果格式化
├── tools/
│   ├── weather.py
│   ├── calculator.py
│   └── registry.py
├── model/
│   └── client.py            # 封装模型调用
├── memory/
│   └── session_store.py     # 历史消息 / 摘要 / 状态
└── frontend/
    └── ...

这个结构的核心思想是:

让每个目录只承担一类变化。

  • prompt 变了,不要改 retriever
  • 工具新增了,不要改 UI
  • 检索策略变了,不要改模型客户端
  • 历史策略变了,不要把 chat 入口全重写一遍

主流程应该长什么样

真正的“主流程”通常只有几十行到一百多行,不应该塞满所有细节。
它更像一个 orchestration coordinator:

def handle_chat(user_msg, history, session_state):
    context = maybe_retrieve(user_msg, session_state)
    messages = build_messages(system_prompt, history, context, user_msg)

    while True:
        response = model.chat(messages, tools=tools)

        if not response.tool_calls:
            return finalize(response)

        for call in response.tool_calls:
            result = execute_tool(call, session_state)
            messages.append(tool_result_message(call.id, result))

这段流程清楚表达了三件事:

  1. 可能先检索
  2. 然后进入模型-工具循环
  3. 最后输出结果

这比把所有细节都混在一个文件里要健康得多。


9. 常见坑:第一次做助手,最容易栽在哪里

先看定义:第一次做 AI 助手,最容易出问题的往往不是“模型太弱”,而是上下文管理、检索质量、工具边界和可观测性没处理好。


坑 1:把所有历史都塞进 context

表现

对话越长越慢,模型还越来越容易“失忆”。

更好的做法

  • 只保留最近 N 轮
  • 更早的内容做摘要
  • 把长期关键信息单独存状态,而不是原样堆历史

坑 2:RAG 接上了,但检索出来的不相关

表现

用户问年假,系统检索到了报销制度;
用户问 VPN,系统拿到的是 IT 值班表。

更好的做法

  • 先检查文档清洗
  • 再检查 chunking
  • 再检查 embedding 模型
  • 再检查 top-k 和 metadata filtering

不要一开始就怀疑“模型太笨”。


坑 3:工具权限全交给模型

表现

模型能请求过宽的参数、访问不该访问的数据、触发不该触发的动作。

更好的做法

  • 在工具层注入用户身份
  • 严格做 schema 校验
  • 高风险动作要求确认
  • 工具只暴露最小必要权限

坑 4:没有日志,看不出错在哪

表现

回答不好时,你不知道问题出在:

  • system prompt
  • 检索结果
  • 工具调用
  • 模型选择
  • 上下文过长
  • 还是某个 API 报错

更好的做法

至少把这些打进日志:

  • user input
  • 触发了哪条路径(直接答 / RAG / 工具)
  • 检索到了哪些文档
  • 调用了哪些工具
  • 模型最终返回了什么
  • 总耗时和 token 用量

原型阶段就开始做最基本的 trace,后面会省很多时间。


坑 5:想一步做成“全自动 Agent”

表现

系统会聊天、会检索、会调工具,但一旦任务稍复杂就开始循环失控、调用过多、结果漂移。

更好的做法

先把单回合能力做稳,再逐步加复杂性:

  1. 先做普通问答
  2. 再加 RAG
  3. 再加少量工具
  4. 再考虑复杂工作流和多工具编排

这是比“一步到位上大 Agent”更稳的路线。


10. 一条真正能落地的迭代路线

先看定义:做 AI 助手最稳的方式,不是一次性做满,而是按“先闭环、再增强、再平台化”的顺序推进。


第一阶段:先跑通闭环

目标:

  • 用户能发问
  • 助手能回答
  • 知识库能检索
  • 工具能调通
  • UI 能展示结果

这阶段最重要的是:
系统能端到端工作。


第二阶段:开始提升质量

你会开始优化:

  • chunking
  • top-k
  • prompt
  • 检索格式
  • 工具描述
  • 历史消息管理
  • 失败提示和降级逻辑

这阶段的核心不是加新功能,而是让已有链路更稳。


第三阶段:加观测、评测和控制

你会逐渐加上:

  • 请求日志
  • prompt 版本管理
  • 样例集回归
  • 工具调用审计
  • 模型路由策略
  • 成本监控

到这一步,系统才开始像“产品基础设施”。


第四阶段:再考虑更强的 Agent 化

例如:

  • 多工具规划
  • 多步任务拆解
  • 工作流状态机
  • 人工确认节点
  • 多模型协同

这时你才真正进入更高级的 AI 应用阶段。


11. 一个最好记住的原则:先做“可靠助手”,再做“聪明代理”

如果你只想记住一句话,那应该是:

一个能稳定回答、稳定检索、稳定调用两个工具的助手,通常比一个号称什么都能做但经常失控的 Agent 更有价值。

原因很简单:

  • 可靠性比炫技更能决定用户是否会继续用
  • 可调试性比复杂度更能决定团队能否继续迭代
  • 明确边界比“全能幻觉”更接近可上线系统

所以,这篇文章真正想传达的不是“怎么堆功能”,而是:

如何用最少的组件,搭出第一套真正可工作的 AI 应用骨架。

只要这个骨架是对的,后面无论你要加:

  • 更复杂的 RAG
  • 更多业务工具
  • 更精细的状态管理
  • 多模型路由
  • Agent 工作流

都会是自然生长,而不是返工重构。


核心概念速查

概念一句话
System Prompt定义助手身份、能力边界和回答原则
RAG先检索相关资料,再把资料注入当前上下文回答
Tool Calling模型输出调用意图,应用执行工具并回填结果
Tool Loop工具调用 → 结果回填 → 模型继续判断的循环
Orchestration负责把 Prompt、RAG、工具调用和历史状态组织成完整流程
Streaming UI让用户边等待边看到生成内容,改善交互体验
Session State保存最近历史、摘要和关键状态,避免会话越聊越乱
MVP Assistant先把最小可用闭环跑通的原型助手

下一篇

Foundation 系列到这里就告一段落了。
你已经具备了从模型原理到 Prompt、从 RAG 到工具调用、从向量数据库到系统架构,再到原型助手搭建的完整基础视角。

接下来最自然的深入方向,就是进入 RAG 专题

  • 什么是 RAG
  • 为什么“检索 + 生成”不只是拼起来这么简单
  • chunking、rerank、多路检索、agentic RAG 分别解决什么问题
  • 如何把知识库问答从“能用”做到“好用”