微信扫码
添加专属顾问
我要投稿
从零开始构建AI Agent?这篇文章用代码说话,带你深入Spring AI的实践世界。 核心内容: 1. 基于Spring AI的AI Agent开发全流程解析 2. RAG检索增强生成与Function Calling工具调用的实现细节 3. 多模块架构设计:从AgentCore到Command & Skill系统
阿里妹导读
文章内容基于作者个人技术实践与独立思考,旨在分享经验,仅代表个人观点。
前言
Linux说过一句很经典的话:Talk is cheap, show me the code.
最近在学习AI Agent开发的时候,填鸭式地被灌输了很多新知识,但是这些新知识就像是漂浮的“空中楼阁”,看得见但摸不着,只知道理论如此但是不知道具体实现为何物。计算机工程的事儿,往往真的听再多毫无体感,看一遍代码就基本一通百通,由此产生一个很神奇的想法:“最好的学习资料是代码,既然我要学AI Agent开发,那就让AI Agent本身帮我生成学习资料。”于是乎,便有了这篇文章,即我本文的项目代码几乎是由AI生成,我在其中的角色只是指挥家与验收员。
开始之前先作一些声明:
1、该项目本身纯作为学习用途的Demo,只是用作展示“理论背后看得见的代码”。
2、Agent的理解较为宽泛,从整体概念层面是包含LLM的,一般Agent开发往往指的是Harness开发,但本文不做具体区分。
3、不深入每个概念的设计哲学,如Skill的渐进式披露,主要关注于实现层面。
4、Function Calling:LLM本身不会调工具,工具调用都是Harness做的;实际上Function Calling是大地基,很多复杂能力都是作为tool的形式包装给LLM的,例如Skill与SubAgent调用。
快速开始
本项目是一个基于Spring AI的AI Agent应用(纯Demo,仅学习用途),集成了 RAG 检索增强生成、Function Calling 工具调用、MCP 协议、SubAgent 子代理、Skill 技能系统等核心能力。本文将从六个核心模块出发,深入剖析其架构设计和实现细节。
代码仓库
github地址:https://github.com/q644266189/aiagentdemo
git clone git@github.com:q644266189/aiagentdemo.git
环境要求
Java 21+
Maven 3.9+
核心模块
模块 |
说明 |
AgentCore |
核心编排器,具备意图识别、记忆管理与大模型调用等能力。 |
ChatMemory |
对话记忆管理,支持三层上下文压缩(摘要压缩 → Assistant 裁剪 → 滑动窗口)。 |
Tool(Function Calling) |
可插拔的工具注册机制,通过 |
RAG |
完整的检索增强生成流水线:文档加载 → 文档分块 → 向量化 → 向量存储 → 多路召回(语义 + BM25 + 查询改写)→ RRF 融合 → Rerank 重排 → LLM → 内容生成 |
Command & Skill |
两种 Markdown 驱动的 Prompt 模板机制:Command 由用户主动调用,Skill 本质作为Tool由 LLM 决策调用。 |
SubAgent |
拥有独立记忆的子代理,支持内部 SubAgent 和外部 IdeaLab Agent 两种形态 |
MCP |
双向 MCP 支持:作为 Client 动态连接外部 MCP 服务,作为 Server 对外暴露服务 |
配置
编辑 src/main/resources/application.properties,配置大模型 API
spring.ai.openai.base-url=https://open.bigmodel.cn/api/paas/v4spring.ai.openai.api-key=你的API密钥spring.ai.openai.chat.options.model=glm-4spring.ai.openai.embedding.options.model=embedding-3
访问
启动成功后,打开浏览器访问:
http://localhost:8080项目内置了一个完整的 Web 聊天界面(src/main/resources/static/index.html),支持:
流式对话:实时逐字输出 AI 回复(SSE)
Markdown 渲染:自动渲染代码块、表格、列表等
命令面板:输入 / 唤起快捷命令列表
会话管理:支持清空对话历史
# 非流式对话curl -X POST http://localhost:8080/api/chat \-H "Content-Type: application/json" \-d '{"message": "你好,介绍一下你的能力", "sessionId": "test-001"}'# 流式对话(SSE)curl -X POST http://localhost:8080/api/chat/stream \-H "Content-Type: application/json" \
一、核心编排器:AgentCore
AgentCore 是整个系统的"大脑",负责编排对话的完整流程:意图识别 → RAG 注入 → 记忆管理 → 模型调用 → 工具执行。
1.1 对话流程
用户输入│▼意图识别(IntentRecognizer)│ 判断:这是知识问答还是通用对话?▼RAG 注入(RagService)│ 如果是知识问答,检索知识库,将参考资料拼入上下文▼记忆管理(ChatMemory)│ 自动摘要压缩 → 构建消息列表▼模型调用(ChatClient + ToolCallbacks)│ LLM 决策:直接回答 or 调用工具?│ 如果调用工具 → 执行工具 → 将结果返回 LLM → 继续决策(ReAct 循环)▼返回最终回复
核心代码(AgentCore.chat()):
public String chat(String sessionId, String userInput) {ChatMemory memory = getOrCreateMemory(sessionId);// 1. 意图识别Intent intent = intentRecognizer.recognize(userInput);// 2. 如果是 RAG 意图,先检索知识库并注入上下文if (intent == Intent.RAG && ragService.isKnowledgeLoaded()) {String ragContext = ragService.query(userInput);if (ragContext != null && !ragContext.isBlank()) {String enrichedInput = "以下是从知识库中检索到的相关参考资料,"+ "请结合这些资料回答用户的问题:\n\n"+ ragContext + "\n\n用户问题:" + userInput;memory.addMessage(new UserMessage(enrichedInput));} else {memory.addMessage(new UserMessage(userInput));}} else {memory.addMessage(new UserMessage(userInput));}// 3. 构建 Prompt 并Loop调用大模型(getMessages 内部自动触发摘要压缩)List<Message> messages = memory.getMessages();Prompt prompt = new Prompt(messages, buildChatOptions());ChatClient.ChatClientRequestSpec requestSpec = chatClient.prompt(prompt);if (!toolCallbacks.isEmpty()) {requestSpec.toolCallbacks(toolCallbacks.toArray(new ToolCallback[0]));}String response = requestSpec.call().content();memory.addMessage(new AssistantMessage(response != null ? response : ""));return response != null ? response : "";}
1.2 Agent Loop
Spring AI已实现Agent Loop。
具体路径为
org.springframework.ai.chat.client.advisor.ToolCallAdvisor#adviseCall
Agent Loop代码片段
boolean isToolCall = false;do {// Before Callvar processedChatClientRequest = ChatClientRequest.builder().prompt(new Prompt(instructions, optionsCopy)).context(chatClientRequest.context()).build();// Next CallprocessedChatClientRequest = this.doBeforeCall(processedChatClientRequest, callAdvisorChain);chatClientResponse = callAdvisorChain.copy(this).nextCall(processedChatClientRequest);chatClientResponse = this.doAfterCall(chatClientResponse, callAdvisorChain);// After Call// TODO: check that this tool call detection is sufficient for all chat models// that support tool calls. (e.g. Anthropic and Bedrock are checking for// finish status as well)ChatResponse chatResponse = chatClientResponse.chatResponse();isToolCall = chatResponse != null && chatResponse.hasToolCalls();if (isToolCall) {Assert.notNull(chatResponse, "redundant check that should never fail, but here to help NullAway");ToolExecutionResult toolExecutionResult = this.toolCallingManager.executeToolCalls(processedChatClientRequest.prompt(), chatResponse);if (toolExecutionResult.returnDirect()) {// Return tool execution result directly to the application client.chatClientResponse = chatClientResponse.mutate().chatResponse(ChatResponse.builder().from(chatResponse).generations(ToolExecutionResult.buildGenerations(toolExecutionResult)).build()).build();// Interrupt the tool calling loop and return the tool execution// result directly to the client application instead of returning// it to the LLM.break;}instructions = this.doGetNextInstructionsForToolCall(processedChatClientRequest, chatClientResponse,toolExecutionResult);}}while (isToolCall); // loop until no tool calls are present
1.3 意图识别
IntentRecognizer 通过 LLM 判断用户输入的意图,目前支持两种:
RAG:用户在问知识库相关的问题,需要先检索知识库再回答
GENERAL:通用对话,直接交给 LLM 处理
意图识别前置的好处是:避免每次对话都触发 RAG 检索,节省不必要的向量检索和 Rerank 开销。
1.4 对话记忆:ChatMemory
每个 sessionId 对应一个独立的 ChatMemory 实例,天然支持多客户端并发。
ChatMemory 设计了三层递进的上下文压缩策略,防止对话过长导致 token 溢出或成本失控:
当历史消息超过 16 条时,自动将较早的消息通过 LLM 总结为一段 300 字以内的摘要,注入到 system prompt 中。原消息从 history 中移除。
核心代码(ChatMemory.getMessages() 和 compressIfNeeded()):
public List<Message> getMessages() {// 在构建消息列表之前,自动尝试摘要压缩compressIfNeeded();List<Message> messages = new ArrayList<>();// 将原始 system prompt 与摘要合并为一条 SystemMessageif (systemMessage != null || (summaryText != null && !summaryText.isBlank())) {String systemContent = systemMessage != null ? systemMessage.getText() : "";if (summaryText != null && !summaryText.isBlank()) {systemContent += "\n\n【以下是之前对话的摘要,请参考】\n" + summaryText;}messages.add(new SystemMessage(systemContent));}// ... 添加历史消息(跳过早期 Assistant 消息)return Collections.unmodifiableList(messages);}private void compressIfNeeded() {if (chatClient == null || history.size() <= COMPRESS_THRESHOLD_MESSAGES) {return;}int compressEndIndex = history.size() - PRESERVE_RECENT_MESSAGES;// 确保不会在 TOOL 消息的前面截断while (compressEndIndex < history.size()&& history.get(compressEndIndex).getMessageType() == MessageType.TOOL) {compressEndIndex--;}if (compressEndIndex <= 0) return;List<Message> messagesToCompress = new ArrayList<>(history.subList(0, compressEndIndex));String newSummary = SummaryCompressor.compress(chatClient, messagesToCompress, summaryText);if (newSummary != null && !newSummary.isBlank()) {this.summaryText = newSummary;history.subList(0, compressEndIndex).clear();}}
这一层的核心设计:
内聚透明:压缩逻辑完全封装在 getMessages() 内部,调用方无感知。压缩器 SummaryCompressor 作为 ChatMemory 的私有静态内部类,不对外暴露;
增量压缩:如果已有历史摘要,新的压缩会将旧摘要与新对话合并总结,避免信息随多次压缩逐渐丢失;
TOOL 消息边界保护:截断时自动避开 TOOL 消息,确保 TOOL 消息始终紧跟在对应的 ASSISTANT 消息后面,不会破坏工具调用上下文。
只保留最近 3 条 Assistant 回复。因为 LLM 的回复通常很长,是 token 消耗的大户,裁剪早期的 Assistant 消息能显著减少上下文体积。
当消息总数超过 maxRounds × 4 时,直接丢弃最早的消息。这是最后一道防线,确保上下文不会无限增长。
三层策略协同工作:摘要压缩优先触发(保留信息),Assistant 裁剪持续生效(精准省 token),滑动窗口兜底(硬性保护)。
1.5 多会话隔离与运行时配置
多会话:ConcurrentHashMap<String, ChatMemory> 按 sessionId 隔离,支持并发
运行时切换模型:通过 API 动态切换模型提供商(如从智谱切到通义千问),无需重启
运行时调参:支持动态调整 temperature、maxTokens、topP 等推理参数
二、Tool 机制(Function Calling)
LLM 只能"想",Tool 让它能"做"。LLM本身是不会去调用各种服务,Agent服务端只是告诉大模型“有哪些工具可以调用”,LLM返回给Agent服务端的是“要去调哪些工具”,真实调用实在Agent服务端。
本项目基于 Spring AI 的 Function Calling 能力,设计了一套可插拔的工具注册机制。
2.1 工具注册机制
所有工具实现统一的 InnerTool 接口:
public interface InnerTool {List<ToolCallback> loadToolCallbacks();}
启动时,Spring 自动扫描所有 InnerTool Bean,调用 loadToolCallbacks() 收集所有工具,统一注册到 AgentCore。新增工具只需实现这个接口,无需修改任何已有代码。
ToolCallbackBuilder 提供了简洁的工具构建 API,将工具名、描述、参数定义(JSON Schema)和执行函数组装为 Spring AI 标准的 ToolCallback。
2.2 工具调用流程
用户:"杭州今天天气怎么样?"│▼LLM 分析意图,决定调用 get_weather 工具│▼Spring AI 自动执行工具:get_weather({"city": "杭州"})│▼工具返回结果:"杭州,晴,22°C"│▼LLM 基于工具结果生成最终回复:"杭州今天天气晴朗,气温 22°C,适合出行。"
Spring AI 的 ChatClient 内置了 ReAct 循环:LLM 可以连续调用多个工具,直到认为信息充足后给出最终回复。整个过程对开发者透明。
2.3 内置工具一览
工具名 |
功能 |
说明 |
|
知识库检索 |
将 RAG 检索能力封装为工具,LLM 可主动检索 |
|
创建子代理 |
创建拥有独立记忆的 SubAgent |
|
与子代理对话 |
在 SubAgent 的独立上下文中继续对话 |
|
销毁子代理 |
释放 SubAgent 资源 |
|
调用 IDEAs 应用 |
调用外部 IdeaLab 平台的 AI 应用(支持多个) |
|
执行技能 |
由 Markdown 文件定义的技能,动态注册 |
|
MCP 工具 |
从外部 MCP Server 发现并注册的工具 |
|
天气查询 |
示例工具 |
|
股票价格查询 |
示例工具 |
三、RAG 模块:检索增强生成
RAG(Retrieval-Augmented Generation)让 Agent 能够基于私有知识库回答问题。
3.1 RAG完整流水线
3.2 文档分块策略
分块质量直接决定检索质量。项目提供了多种分块策略,分为确定规则分块和智能分块两类:
策略 |
原理 |
适用场景 |
TextSplitter(默认) |
递归语义分块,按标题 → 段落 → 句子 → 固定字符的优先级依次尝试切分 |
通用文档,兼顾语义完整性 |
FixedSizeSplitter |
按固定字符数切分 |
结构不明确的纯文本 |
ParagraphSplitter |
按段落(连续换行)切分 |
段落结构清晰的文档 |
SentenceSplitter |
按句子(句末标点)切分 |
需要细粒度检索的场景 |
SlidingWindowSplitter |
滑动窗口切分,相邻块有重叠 |
需要保留上下文连续性 |
策略 |
原理 |
适用场景 |
SemanticChunkSplitter |
基于语义相似度判断切分点 |
语义边界不明确的长文本 |
PropositionSplitter |
将文本拆解为独立命题 |
需要精确事实检索 |
AgenticSplitter |
使用 LLM 判断最佳切分方式 |
复杂混合格式文档 |
默认使用 TextSplitter(递归语义分块),分块大小 500 字符,重叠 50 字符。
3.3 检索流程核心代码
RagService.query() 封装了完整的检索流程:
public String query(String question) {// 1. 多路召回(语义 + BM25 + 查询改写,共 9 个候选)List<Document> candidates = multiRecaller.recall(question, RECALL_CANDIDATE_COUNT);// 2. Rerank 重排(取最相关的 3 个)List<Document> relevantDocuments = llmReranker.rerank(question, candidates, TOP_K);// 3. 拼接上下文StringBuilder contextBuilder = new StringBuilder();for (int i = 0; i < relevantDocuments.size(); i++) {contextBuilder.append("【参考资料 ").append(i + 1).append("】\n");contextBuilder.append(relevantDocuments.get(i).getContent()).append("\n\n");}return contextBuilder.toString().trim();}
3.4 召回策略
单一召回策略总有盲区,项目使用多路召回 + RRF 融合的方案:
召回器 |
原理 |
擅长 |
SemanticRetriever |
基于 EmbeddingModel 的向量余弦相似度检索 |
语义相近但措辞不同的查询 |
Bm25Retriever |
基于 BM25 算法的关键词匹配(TF-IDF 变体) |
精确关键词匹配 |
QueryRewriteRetriever |
先用 LLM 将问题改写为 3 种不同表达,再分别做向量召回 |
扩大语义覆盖面 |
三路召回结果通过 RRF(Reciprocal Rank Fusion) 算法融合:
// MultiRecaller 核心逻辑public List<Document> retrieve(String query, int topK) {Map<String, Double> rrfScores = new HashMap<>();Map<String, Document> keyToDocument = new LinkedHashMap<>();for (Recaller retriever : retrievers) {List<Document> results = retriever.retrieve(query, PER_ROUTE_CANDIDATE_COUNT);// RRF 公式:score(d) = Σ 1 / (k + rank),k=60 为平滑常数accumulateRrfScores(results, rrfScores, keyToDocument);}return rrfScores.entrySet().stream().sorted(Map.Entry.<String, Double>comparingByValue().reversed()).limit(topK).map(entry -> keyToDocument.get(entry.getKey())).toList();}
RRF 只看排名不看绝对分数,天然适合融合不同算法的结果。
3.5 Rerank 重排
多路召回后通常有 9 个候选文档,通过专用的 Rerank 模型精排,取最相关的 3 个。
3.6 向量存储
VectorStore 是一个轻量级的内存向量存储实现,使用 Spring AI 的 EmbeddingModel 生成向量,通过余弦相似度检索。适合中小规模知识库,生产环境可替换为 Milvus、Pinecone 等专业向量数据库。
四、Command 与 Skill:两种 Prompt 模板机制
Command 和 Skill 都是基于 Markdown 文件定义的 Prompt 模板,但它们的设计理念和使用方式截然不同。
4.1 Skill:LLM 自主调用的工具
Skill 文件使用 YAML Front Matter + Prompt 模板 格式:
---name: summarizedescription: 对用户提供的文本内容进行摘要总结---请对以下文本进行摘要总结,提取核心要点:{{input}}
SkillManager 在启动时扫描 classpath:skill/*.md,解析元数据后由 SkillTool 将每个技能转换为 ToolCallback 注册到 Agent。LLM 在对话中根据 description自主判断是否需要调用某个技能。
4.2 Command:用户主动调用的快捷指令
Command 文件是纯 Prompt 模板,文件名即为命令名:
请对以下代码进行 Code Review,从代码质量、潜在 Bug、性能、可读性等维度给出改进建议:{{input}}
CommandManager 在启动时扫描 classpath:command/*.md,加载到内存。用户通过 REST API(POST /api/command/execute)主动指定命令名来执行。
4.3 核心区别对比
维度 |
Command |
Skill |
设计理念 |
用户快捷指令 |
LLM 可调用的工具 |
文件格式 |
纯 Prompt 模板 |
Front Matter(name + description)+ Prompt |
是否注册为工具 |
❌ 不注册 |
✅ 注册为 ToolCallback |
调用触发方 |
用户主动指定命令名 |
LLM 根据 description 自主决策 |
执行路径 |
用户 → Controller → AgentCore |
用户 → AgentCore → LLM 决策 → SkillTool |
适用场景 |
用户明确知道需要什么功能 |
需要 LLM 理解上下文后智能判断 |
一句话总结:
Command 是"用户告诉 Agent 做什么",Skill 是"Agent 自己判断该做什么"。两者互补——Command 提供确定性的快捷入口,Skill 提供智能化的能力扩展。
五、SubAgent:独立记忆的子代理
5.1 为什么需要 SubAgent
有些任务需要独立的上下文。比如用户说"帮我写一篇技术文章",这个任务可能需要多轮对话来完善,但不应该污染主对话的记忆。SubAgent 就是为此设计的。
5.2 记忆隔离机制
SubAgent 的核心是记忆隔离:每个 SubAgent 拥有独立的 ChatMemory 实例,与主 Agent 的记忆完全隔离。
public SubAgent(String id, String name, String systemPrompt, ChatClient chatClient) {this.memory = ChatMemory.forSubAgent(); // 独立记忆!this.memory.setSystemPrompt(systemPrompt);// ...}
SubAgent 共享主 Agent 的 ChatClient(即共享同一个大模型连接),但对话历史完全独立。这意味着:
SubAgent 内部的多轮对话不会影响主对话的上下文
主 Agent 可以同时管理多个 SubAgent,各自互不干扰
SubAgent 销毁后,其记忆随之释放
5.3 交给LLM:Tool
SubAgent 的能力通过 3 个工具暴露给主 Agent,本质上就是 Function Calling,由LLM决策启用SubAgent:
工具 |
参数 |
说明 |
|
name、system_prompt、task |
创建 SubAgent 并执行首个任务 |
|
agent_id、message |
与已有 SubAgent 继续对话 |
|
agent_id |
销毁 SubAgent,释放资源 |
主 LLM 根据对话上下文自主决定是否需要创建 SubAgent。整个生命周期(创建 → 多轮对话 → 销毁)都由主 LLM 通过工具调用来驱动。
六、MCP:连接一切外部服务
MCP(Model Context Protocol) 是 Anthropic 提出的开放协议,让 AI 应用能够标准化地连接外部工具和数据源。本项目同时实现了 MCP Server(对外暴露能力)和 MCP Client(连接外部服务)。
6.1 MCP Server:对外暴露知识库检索能力
项目通过 SimpleMcpServer 对外提供知识库检索工具,其他 AI 应用可以通过 MCP 协议来调用:
工具:knowledge_query
参数 |
类型 |
说明 |
|
String |
检索关键词 |
|
String |
知识分类(java_basic / jvm / concurrent / spring / design_pattern / all) |
|
int |
返回的最大结果条数,默认 3 |
内部调用 RagService 执行检索,将结果格式化后返回。这意味着本项目的 RAG 能力可以被任何支持 MCP 协议的 AI 应用复用。
6.2 MCP Client:动态连接外部 MCP 服务
McpClient 封装了连接外部 MCP Server 的完整逻辑:
核心代码(McpClient.connect()):
public ToolCallback[] connect(String serverUrl) {McpSyncClient mcpClient;McpSchema.InitializeResult initResult;// 优先尝试 Streamable HTTP,失败后回退到 SSEtry {mcpClient = connectWithStreamableHttp(serverUrl);initResult = mcpClient.initialize();} catch (Exception streamableException) {mcpClient = connectWithSse(serverUrl);initResult = mcpClient.initialize();}// 自动发现远程工具SyncMcpToolCallbackProvider provider = SyncMcpToolCallbackProvider.builder().mcpClients(mcpClient).build();ToolCallback[] toolCallbacks = provider.getToolCallbacks();// 持久化 URL,下次启动自动恢复store.add(serverUrl);return toolCallbacks;}
关键特性:
传输协议自动适配:优先 Streamable HTTP(2025-03-26 规范),失败自动回退 SSE(2024-11-05 规范)
工具自动发现:连接成功后自动获取远程工具,转换为 ToolCallback 注册到 Agent
持久化与自动恢复:URL 持久化到 mcp-servers.json,应用重启时自动重连
运行时动态管理:通过 REST API 在运行时动态管理 MCP 连接:
接口 |
方法 |
说明 |
|
POST |
连接新的 MCP 服务,工具立即可用 |
|
POST |
断开 MCP 服务,移除对应工具 |
|
GET |
查看所有 MCP 服务及其工具列表 |
结尾感言
LLM就像一个问答黑箱,不管内部支持多丰富的能力,对使用者本质只有一个能力:“你问,我答”。
使用者做的事情几乎是一致的:调整输入给LLM的内容,尽量让其输出预期内的内容。而对于“调整输入内容”这一块看似轻巧,实际上正是工程化发展的源泉,从Prompt Engineering到Context Engineering到Harness Engineering本质解决的就是“有限的上下文窗口中该放什么内容”。
脑暴枚举目前上下文窗口可能放的内容有:系统提示词、工具定义、历史对话、参考文档等。目前AI Agent正高速发展,最终浪淘沙到尽头什么会是最终答案不由而知,但是其中工具定义可能会走到最后。至少目前而言Function Calling是Harness的大地基,实际上很多能力的实现都是基于Function Calling,比如Skill本质就是一种Tool,而RAG、SubAgent与外部MCP服务等能力在工程实践中也大量被做成一种Tool由LLM决策调用。
53AI,企业落地大模型首选服务商
产品:场景落地咨询+大模型应用平台+行业解决方案
承诺:免费POC验证,效果达标后再合作。零风险落地应用大模型,已交付160+中大型企业
2026-04-22
我搭建了Karpathy的个人知识库,但发现成本高速度慢,我用一个更好的方案替代了。
2026-04-21
多轮对话时,RAG反复做重复召回,模型层与Milvus层分别如何解决?
2026-04-20
Codeindex · 让大模型更好地理解你的代码
2026-04-13
用RAG的思路做agent知识管理,为什么跑不通
2026-04-12
YC CEO 的 AI 记住了 3000 个人
2026-04-10
AI 答疑助手优化实践:从 RAG 到 LightRAG 的全链路升级
2026-04-09
阿里云百炼「记忆库」正式上线,让龙虾真正记住你!
2026-04-09
用Karpathy的设计哲学重构龙虾助手的知识库架构
2026-02-13
2026-02-03
2026-02-03
2026-02-06
2026-02-06
2026-02-02
2026-04-06
2026-01-28
2026-02-05
2026-02-06
2026-04-21
2026-03-17
2026-03-11
2026-02-22
2026-02-15
2026-02-04
2026-02-03
2026-01-19