面试中很容易被问到为什么选择了某个技术而没选择另外一个技术,所以在项目进行之前要有架构设计与技术选型说明书,方便在面试中有条理的回答。

1.项目总体架构图

2. 核心模块技术选型矩阵

模块一:大模型底层调用(LLM Client)

候选技术 方案A:官方SDK(openai) 方案B:requests裸调(我的选择
实现方式 client.chat.completions.create() 手写requests.post + 手写SSE逐行解析
优点 代码量极少,开箱即用 完全掌控HTTP细节,彻底看懂流式协议
缺点 屏蔽了重试、超时、流式解析的具体实现 代码量大,需手动处理Chunk边界
  • 为什么不用官方SDK?

  • 因为面试和实际生产不同。在生产中我会用SDK,但在这个项目中,我的核心目标是搞懂底层原理。使用requests裸调让我必须手动处理iter_lines解析data: [DONE],手动捕获429状态码做指数退避。这种'手撕协议'的过程让我深刻理解了SSE(Server-Sent Events)不是魔法,就是标准的HTTP长连接。如果将来SDK出Bug,我能直接看懂HTTP抓包去排查。


模块二:Agent架构框架(Agent Loop)

候选技术 方案A:LangGraph/LangChain 方案B:纯Python While循环(我的选择
实现方式 StateGraph + add_node + compile while max_iterations: + if tool_calls:
优点 支持复杂分支、检查点、持久化 极轻量,每一行报错都能立刻定位
缺点 源码黑盒,出问题难排查,依赖重 需手动实现循环终止条件和状态合并
  • 既然LangGraph是主流,你为什么非手搓?

  • 我的选型原则是奥卡姆剃刀。本项目Agent的拓扑结构是'规划-执行-观察'线性循环,不涉及复杂的条件分支或并行子图。用LangGraph属于'杀鸡用牛刀',而且它内部复杂的Pregel执行器会掩盖状态流转的本质。

    我手写while循环后,发现了一个关键认知:Agent的状态管理其实就是维护messages这个List。LangGraph的add_messages Reducer,底层无非就是list.extend()。这种认知让我在调试多轮对话时能精准预测内存中的State变化,而不是在黑盒外猜。


模块三:向量数据库(RAG Storage)

候选技术 方案A:Chroma / Pinecone 方案B:NumPy矩阵 + JSON文件(我的选择
实现方式 collection.query() np.dot(embeddings, query_vec) / (norm * norm)
优点 支持海量数据、HNSW索引、分布式 纯数学运算,零网络开销,完全本地化
缺点 引入外部依赖,需维护服务进程 暴力搜索,数据量超10万条时性能下降
  • Chroma这么成熟,为什么不用?

  • 这就是典型的场景驱动选型。我的知识库预计只有1000-2000个文本块(个人笔记规模)。在这种规模下,暴力计算余弦相似度的耗时(毫秒级)和HNSW索引的耗时差距微乎其微。

    但我选择NumPy手算有一个无法替代的面试价值:我手写过cosine_similarity = A·B / (||A|| ||B||),所以我能清楚地告诉面试官——RAG检索的本质是线性代数,而不是神秘的'魔法API'。如果将来我转去做搜推引擎,这个数学基础是通用的。


模块四:MCP协议实现(Model Context Protocol)

候选技术 方案A:官方MCP Python SDK 方案B:手写JSON-RPC 2.0 + stdio(我的选择
实现方式 from mcp.server import Server sys.stdin.read() + json.dumps + sys.stdout.write
优点 开箱即用,自动处理协议版本 完全搞懂JSON-RPC 2.0的消息格式
缺点 抽象层次高,难以理解底层通信 需手动处理消息边界(换行符分隔)
  • MCP是新技术,官方有SDK为什么不用?

  • 我的目标不是'接入MCP',而是'成为MCP的贡献者'。我必须搞懂MCP的本质:它就是定义在stdioWebSocket上的JSON-RPC 2.0协议。

    手写实现让我看清了三个核心Method:initialize(握手)、tools/list(暴露工具)、tools/call(执行调用)。我把Tools注册进MCP Server后,用Claude Desktop测试,看着JSON报文在终端打印出来,那一刻我彻底明白了进程间通信(IPC)协议标准化的意义。如果只用SDK,我永远不会有这种'降维打击'的快感。


模块五:Web服务框架(API Server)

候选技术 方案A:FastAPI(异步) 方案B:Flask + Gunicorn(我的选择
实现方式 async def chat(): + await def chat(): + yield (SSE流式)
优点 高性能并发,自动OpenAPI文档 同步阻塞逻辑简单,完美适配requests
缺点 异步调试复杂,对新手不友好 高并发下(QPS>100)性能不如FastAPI
  • 现在新项目都用FastAPI,为什么选Flask?

  • 选型要匹配调用链路。我的Agent循环是同步阻塞的(调用OpenAI API等待返回),即便用了FastAPI的async/await,底层的httpx异步客户端如果没配好,一样会阻塞事件循环。反而Flask搭配gunicornsync模式,利用多进程(-w 4)处理并发,架构更清晰,也更容易排查死锁。

    而且我的流式输出(SSE)用Flask的Response(generate())生成器实现得极其优雅。如果将来真要扛高并发,我会水平扩展(多部署几个Flask实例+nginx负载均衡),而不是在单机异步上死磕,这在生产中更实用。


模块六:Skills vs Tools 的架构分层

你的Tools和Skills有什么区别?

这是我在架构上做的最重要的分层解耦

  • Tools(原子工具):只做一件事,不包含业务判断。比如read_file(path)只返回字符串,write_file(path, content)只写磁盘。它们不具备智能,只提供能力。

  • Skills(技能编排):是硬编码的工作流。比如我的weekly_report_skill,它做了三件事:①调用read_file读取本周日志;②调用LLM接口(不带tools)进行文本提炼;③调用write_file保存Markdown。

为什么不用Agent代替Skills? 因为Agent规划(Planning)太随机,3次调用可能有2次格式不对。对于标准化高频操作(如写日报),我用Skills固定死流程,保证100%成功率。只有面对陌生用户问题时,我才启动Agent进行动态规划。这是混合式架构,兼顾了稳定性和灵活性。

3. 数据流设计

也就是一条请求进来之后的全流程:

  1. 用户输入 → API (Flask) 接收。

  2. Agent规划器while第一轮,不带Tools)输出plan: "需要先查天气,再算温差"

  3. Agent执行器while第二轮,带Tools)调用get_weather → 结果存进messages

  4. Agent执行器while第三轮)调用calculator → 结果存进messages

  5. Agent反思器(检查messages里的工具结果是否为空,若空则重试)。

  6. 最终输出:返回自然语言给用户。

  7. 旁路RAG:如果用户输入含"查一下我的笔记",Agent会先调embedder,在NumPy矩阵里算余弦相似度,召回的文本块作为system前缀塞进messages


4. 技术栈总览

层级 我的技术选型 面试防怼话术(为什么不用别的)
网络协议 裸HTTP + 手写SSE SDK屏蔽了流式解析,遇到[DONE]错位我无法排查
Agent while循环 + messages维护 LangGraph太重,线性循环无需有向无环图(DAG)
向量存储 NumPy + JSON 数据量<1万条,暴力搜索精度最高,无网络开销
Embedding sentence-transformers 开源离线,避免调用API被限流,且可控
MCP 手写JSON-RPC 官方SDK依赖注入复杂,无法debug协议层
Web框架 Flask + Gunicorn Agent是同步阻塞型,用异步反而增加心智负担
部署 轻量云 + systemd 不用容器化,减少依赖冲突,让进程管理可视化

5. WBS(工作分解结构)

  1. Week 1:实现core/llm_client.py(非流式+流式),手写测试脚本直接跑通API。

  2. Week 2:实现rag/全部模块,手写余弦相似度,测试检索Recall。

  3. Week 3:实现tools/全部原子工具,每个工具写独立单元测试(用assert)。

  4. Week 4:实现core/agent_loop.py,挂载Tools,实现多轮调用。

  5. Week 5:实现skills/,硬编码一个周报技能,验证稳定性。

  6. Week 6:实现mcp/,启动本地Server接入Claude Desktop。

  7. Week 7:写api/routes.py,封装Flask接口。

  8. Week 8:跑通eval/评测,生成报告,部署上线。

Logo

小龙虾开发者社区是 CSDN 旗下专注 OpenClaw 生态的官方阵地,聚焦技能开发、插件实践与部署教程,为开发者提供可直接落地的方案、工具与交流平台,助力高效构建与落地 AI 应用

更多推荐