Common Lisp集成LLM实战:构建AI客户端与REPL智能助手
1. 项目概述当古老的Lisp遇见现代的LLM如果你是一位Common Lisp的开发者看到现在AI领域如火如荼尤其是大语言模型LLM几乎成了所有技术栈的“标配”心里会不会有点痒会不会觉得自己的Lisp世界和外面的AI浪潮之间隔着一道无形的墙我最初就是这么想的。Common Lisp这门拥有数十年历史、以强大表达能力和宏系统著称的语言在数据处理、符号计算、快速原型开发上有着独特的魅力。然而当我想把OpenAI的GPT或者本地部署的Llama模型集成到我的Lisp项目中时却发现社区资源远不如Python、JavaScript那样丰富。难道Lisp开发者就只能旁观吗当然不是。“时代在召唤——Common Lisp调用LLM”这个项目正是为了解决这个痛点。它的核心目标就是为Common Lisp社区搭建一座通向现代LLM服务的桥梁。无论是想在你的Lisp应用中添加一个智能对话功能还是想用Lisp优雅地处理和分析LLM返回的结构化数据甚至是构建基于LLM的Lisp原生AI智能体Agent这个探索都将为你提供一套可行的思路和实用的代码片段。这不仅仅是简单的API封装更是思考如何用Lisp的哲学例如代码即数据、强大的宏、交互式开发来更优雅地驾驭LLM的能力。接下来我将从设计思路、核心实现、到实战踩坑完整地分享如何让Common Lisp顺畅地与LLM对话。2. 核心设计思路与架构选型在开始敲代码之前我们需要明确几个关键的设计决策。这些决策决定了后续实现的复杂度、灵活性和性能。2.1 协议与传输层HTTP Client的选择LLM服务提供商如OpenAI、Anthropic、以及各类开源模型的本地API绝大多数都提供基于HTTP的RESTful API。因此在Common Lisp中调用LLM首要任务就是选择一个稳定、易用的HTTP客户端库。经过对比我主要推荐两个选择Dexador这是目前Common Lisp社区最活跃、功能最全面的HTTP客户端之一。它的API设计友好支持HTTPS、异步请求、连接池等现代特性并且对JSON的处理有很好的支持通常结合jonathan或cl-json库。对于大多数项目Dexador是首选。Drakma一个更老牌、更轻量级的HTTP客户端。它在简单场景下非常可靠但功能上不如Dexador丰富。如果你的项目依赖已经包含了Drakma或者需求极其简单它也是一个可选项。注意选择Dexador时请确保你的Quicklisp发行版足够新或者直接从其Git仓库安装以获得最好的兼容性。为什么选择Dexador除了功能全面更重要的是它的错误处理和超时机制更完善。调用远程API网络不稳定、服务端响应慢是常态一个健壮的客户端必须能妥善处理这些情况。Dexador提供了:timeout等参数能让我们更好地控制请求行为。2.2 数据序列化与JSON共舞LLM API的请求体和响应体基本都是JSON格式。Common Lisp处理JSON主要有两种范式将JSON映射到Lisp对象反序列化使用如cl-json或jonathan库将JSON字符串转换成Lisp的列表list、哈希表hash-table等结构方便后续处理。将Lisp对象编码为JSON序列化将我们构建好的Lisp请求参数同样是列表或哈希表编码成JSON字符串发送给API。jonathan库因其高性能和简洁的API近年来备受青睐。它允许你使用Lisp的list和alist关联列表来自然地表示JSON对象编码解码几乎是无感的。设计考量我们不应该在业务代码中到处散落HTTP请求和JSON解析的细节。一个好的设计是抽象出一个协议层。这一层负责构建符合特定LLM API要求的HTTP请求头如Authorization: Bearer api-key。将Lisp数据结构的请求参数序列化为JSON。发送HTTP请求并处理状态码例如遇到429速率限制错误时自动重试或报错。将响应的JSON正文反序列化为Lisp数据结构或者直接提取出我们关心的文本内容。这样上层的业务代码只需要关心“我想问模型什么问题”而不必理会底层的网络和格式细节。2.3 模型抽象与多提供商支持不同的LLM提供商其API端点、参数名称、响应格式都有差异。例如OpenAI的Chat Completion接口参数叫messages而Anthropic的Claude接口参数可能叫prompt。我们不能把提供商特定的逻辑硬编码得到处都是。因此引入一个模型抽象层是至关重要的。我们可以定义一个通用的LLM-MODEL类或结构体包含如name,provider,api-base-url,api-key等属性。然后为每个支持的提供商如OpenAI、Anthropic、Ollama实现一个具体的后端适配器。这个适配器的职责是知道如何将该提供商的通用请求参数如消息列表、模型名、温度转换为其特定API所需的格式。知道如何解析该提供商返回的响应并提取出标准化的“回复内容”和“使用量”tokens信息。通过这种设计我们可以实现一个统一的函数比如(generate-chat-completion model messages :temperature 0.7)而函数内部会根据model的具体类型分派到对应的适配器去执行。这为未来支持更多LLM服务打下了坚实的基础。3. 核心实现构建Common Lisp的LLM客户端理论说得再多不如一行代码。让我们从最简单的开始逐步构建一个可用的模块。3.1 基础环境搭建与依赖管理首先确保你有一个可用的Common Lisp环境如SBCL、CCL和Quicklisp。然后在你的项目.asd文件或REPL中加载必要的库。;; 在你的 .asd 文件里 :depends-on (#:dexador #:jonathan #:babel #:quri) ;; 或者在 REPL 中快速加载 (ql:quickload (:dexador :jonathan :babel :quri))dexador: HTTP客户端。jonathan: JSON编码/解码。babel: 字符编码转换有时处理非ASCII文本需要。quri: URI构造与处理库用于优雅地构建请求URL。3.2 实现一个最简化的OpenAI API调用我们先抛开复杂的抽象实现一个直接调用OpenAI Chat API的函数。这能让我们立刻看到效果理解整个流程。(defparameter *openai-api-key* (uiop:getenv \OPENAI_API_KEY\)) (defparameter *openai-api-url* \https://api.openai.com/v1/chat/completions\) (defun call-openai-simple (prompt key (model \gpt-3.5-turbo\) (temperature 0.7)) \一个最简单的OpenAI调用函数。\ (unless *openai-api-key* (error \请设置环境变量 OPENAI_API_KEY\)) (let* ((headers ((\Authorization\ . ,(format nil \Bearer ~a\ *openai-api-key*)) (\Content-Type\ . \application/json\))) (data (jonathan:to-json (:model ,model :messages ((:role \user\ :content ,prompt)) :temperature ,temperature))) (response (dex:post *openai-api-url* :headers headers :content data :want-stream nil))) ; 注意want-stream参数 ;; dexador默认返回的是 (values body status headers uri stream) ;; 我们通常只关心body (let ((response-body (jonathan:parse (first response)))) ;; 从复杂的响应结构中提取出助理的回复内容 (getf (getf (first (getf response-body :choices)) :message) :content))))代码解析与实操要点API密钥安全永远不要将API密钥硬编码在代码中。这里通过uiop:getenv从环境变量读取这是最佳实践。你也可以使用类似cl-dotenv的库来管理。JSON构建我们使用反引号backtick和逗号comma构建了一个Lisp列表其结构完全对应OpenAI API所需的JSON。jonathan:to-json会将其转换为字符串。注意messages是一个列表里面包含一个角色为\user\的消息。Dexador调用dex:post函数发起POST请求。关键参数:want-stream nil表示我们不需要流式响应等待完整响应返回。对于简单的文本补全这足够了。如果你需要处理流式输出一个字一个字地返回则需要将其设为t并处理返回的流stream。响应解析dex:post返回多个值第一个是响应体字符串。我们用jonathan:parse将其解析为Lisp的property listplist。OpenAI的响应结构是{:choices [{:message {:content \...\}}]}所以我们用一系列getf来钻取数据。错误处理这个简单版本没有错误处理。如果API返回错误如401认证失败、429限速dex:post会抛出dex:http-request-failed条件。在生产代码中你必须用handler-case或handler-bind来捕获并处理它。在REPL里测试一下CL-USER (call-openai-simple \用Common Lisp写一个Hello World函数\) \当然以下是一个简单的 Common Lisp Hello World 函数定义\\n\\nlisp\\n(defun hello-world () \\n (format t \\\Hello, World!~%\\\))\\n\\n\\n你可以调用 (hello-world) 来执行它它会在标准输出打印 \Hello, World!\。\看你的Common Lisp环境已经能和GPT对话了3.3 构建健壮且通用的客户端模块简单版本能用但远远不够健壮和通用。接下来我们构建一个更完善的模块。3.3.1 定义核心协议与模型抽象(defpackage :cl-llm (:use :cl) (:export #:llm-model #:make-openai-model #:generate-chat-completion #:with-llm-model)) (in-package :cl-llm) ;;; 定义一个通用的LLM模型类 (defclass llm-model () ((name :initarg :name :reader model-name) (provider :initarg :provider :reader model-provider) ; :openai, :anthropic, :ollama等 (api-key :initarg :api-key :reader model-api-key) (base-url :initarg :base-url :reader model-base-url) (default-parameters :initarg :default-parameters :initform () :reader model-default-parameters)) (:documentation \表示一个LLM模型的通用类。\)) ;;; 具体OpenAI模型的构造函数 (defun make-openai-model (key (name \gpt-3.5-turbo\) (api-key (uiop:getenv \OPENAI_API_KEY\))) (make-instance llm-model :name name :provider :openai :api-key api-key :base-url \https://api.openai.com/v1\ :default-parameters (:temperature 0.7 :max-tokens 500)))3.3.2 实现OpenAI适配器与统一接口现在我们实现一个分派机制和OpenAI适配器。;;; 通用的消息结构用于构建对话历史 (defstruct (chat-message (:conc-name msg-)) role ; \system\, \user\, \assistant\ content) ;;; 主函数生成聊天补全 (defgeneric generate-chat-completion (model messages key allow-other-keys) (:documentation \根据给定的模型和消息历史生成回复。\)) ;;; OpenAI适配器的具体实现 (defmethod generate-chat-completion ((model llm-model) messages key (temperature nil) (max-tokens nil) (stream nil)) (unless (eql (model-provider model) :openai) (error \Provider ~a not supported by this method.\ (model-provider model))) (let ((api-key (model-api-key model)) (base-url (model-base-url model))) (unless api-key (error \API key for model ~a is not set.\ (model-name model))) (let* ((url (format nil \~a/chat/completions\ base-url)) (headers ((\Authorization\ . ,(format nil \Bearer ~a\ api-key)) (\Content-Type\ . \application/json\))) ;; 合并默认参数和传入的参数 (params (append (model-default-parameters model) (when temperature (:temperature ,temperature)) (when max-tokens (:max-tokens ,max-tokens)) (:model ,(model-name model) :messages ,(mapcar (lambda (msg) (:role ,(msg-role msg) :content ,(msg-content msg))) messages) :stream ,stream))) (json-data (jonathan:to-json params))) (multiple-value-bind (body status-code) (dex:post url :headers headers :content json-data :want-stream stream) ; 注意流式处理 (if stream ;; 流式响应处理高级主题此处简化 (progn (format t \~%[Streaming response...]~%\) ;; 这里需要循环读取流解析Server-Sent Events (SSE) ;; 为简化我们先不实现完整流式仅提示 (error \Streaming response handling not fully implemented in this example.\)) ;; 非流式响应处理 (if ( status-code 200) (let ((response-json (jonathan:parse body))) ;; 提取回复内容和使用量 (values (getf (getf (first (getf response-json :choices)) :message) :content) (getf response-json :usage))) ;; 处理错误 (error \API request failed with status ~a: ~a\ status-code body)))))))关键改进与经验参数合并函数优先使用调用时传入的temperature等参数如果未传入则使用模型对象中存储的default-parameters。这提供了灵活性。结构化消息我们定义了chat-message结构体使构建多轮对话历史更清晰。例如(list (make-chat-message :role \system\ :content \你是一个Common Lisp专家。\) (make-chat-message :role \user\ :content \如何定义宏\))流式响应占位代码中预留了流式响应stream t的处理分支。OpenAI的流式响应使用Server-Sent Events (SSE)格式处理起来更复杂需要逐块读取和解析。对于初版可以先实现非流式。返回多个值函数使用values返回了回复内容和使用量token数。这在计费和调试时非常有用。3.3.3 添加错误处理与重试机制网络请求必须考虑失败。我们可以定义一个宏或包装函数来添加重试逻辑。(defun call-api-with-retry (api-call-fn key (max-retries 3) (retry-delay 1)) \包装API调用函数在遇到可重试错误时自动重试。\ (loop for retry-count from 0 to max-retries do (handler-case (return-from call-api-with-retry (funcall api-call-fn)) (dex:http-request-failed (c) (let ((status (dex:response-status c))) (cond (( status 429) ; 速率限制 (format *error-output* \~%Rate limited. Retrying after ~a seconds...\ retry-delay) (sleep retry-delay) (incf retry-delay 2)) ; 退避策略延迟递增 (( status 500) ; 服务器错误 (if ( retry-count max-retries) (progn (format *error-output* \~%Server error ~a. Retry ~a/~a...\ status (1 retry-count) max-retries) (sleep retry-delay)) (error \Server error ~a after ~a retries.\ status max-retries))) (t ; 客户端错误如401, 404不应重试 (error c))))) (error (c) ; 其他错误如网络超时 (if ( retry-count max-retries) (progn (format *error-output* \~%Network error: ~a. Retry ~a/~a...\ c (1 retry-count) max-retries) (sleep retry-delay)) (error \Failed after ~a retries: ~a\ max-retries c))))) finally (error \Max retries (~a) exceeded.\ max-retries))) ;;; 修改 generate-chat-completion 方法用 call-api-with-retry 包装核心请求 (defmethod generate-chat-completion :around ((model llm-model) messages key allow-other-keys) (declare (ignore messages)) (call-api-with-retry (lambda () (call-next-method)) ; 调用主方法 :max-retries 3 :retry-delay 2))实操心得错误处理是生产级代码的基石。对于429速率限制和5xx服务器内部错误这类暂时性错误采用指数退避策略进行重试是标准做法。这里我们用了简单的递增延迟。更复杂的系统可能会使用更精细的退避算法。对于401未授权、404未找到这类客户端错误重试是没用的应该立即失败并给出明确错误信息。4. 进阶应用与场景探索有了基础的客户端我们就可以探索一些更有趣的应用场景展示Lisp与LLM结合的魅力。4.1 场景一交互式REPL助手Common Lisp的REPL读取-求值-打印循环是其灵魂。我们可以构建一个REPL助手让你在编码时随时向LLM提问。(defun repl-ai-helper (key (model (make-openai-model))) \启动一个简单的REPL将输入的问题发送给LLM并打印回答。\ (format t \~% Common Lisp REPL AI Helper ~%\) (format t \Type your question (or quit to exit).~%~%\) (loop for query (progn (format t \ \) (read-line)) until (string-equal query \quit\) do (handler-case (let ((response (generate-chat-completion model (list (make-chat-message :role \user\ :content query))))) (format t \~%~a~%~%\ response)) (error (c) (format t \[ERROR] ~a~%~%\ c)))))这个简单的循环让你可以在REPL里直接和GPT对话询问Lisp语法、算法实现甚至让它帮你解释错误信息。4.2 场景二代码分析与文档生成利用LLM强大的代码理解能力我们可以编写一个函数让它分析一个Lisp文件中的函数并自动生成文档字符串。(defun generate-docstring-for-function (function-name model) \为指定的函数名符号生成文档字符串。\ (let* ((source (or (ignore-errors (function-lambda-expression function-name)) (format nil \(defun ~a ...)\ function-name))) ; 简化处理 (prompt (format nil \你是一个Common Lisp专家。请为以下函数定义编写一个清晰的、符合Common Lisp风格的文档字符串。文档字符串应描述函数的功能、参数和返回值。~%~%函数定义~a~%~%请只输出文档字符串内容不要有其他解释。\ source))) (generate-chat-completion model (list (make-chat-message :role \user\ :content prompt)) :temperature 0.3))) ; 降低温度使输出更确定、更规范思路解析这个函数首先尝试获取函数的源码这依赖于具体实现function-lambda-expression并非总是可用生产环境需要更稳健的方法如从源代码文件读取。然后它构造一个非常具体的提示prompt要求LLM扮演Lisp专家并只输出文档字符串。通过设置较低的temperature如0.3我们可以得到更稳定、格式更统一的输出。4.3 场景三结构化数据提取与RAG雏形LLM在从非结构化文本中提取结构化信息方面非常出色。假设我们有一堆Lisp相关的邮件列表或论坛帖子文本我们可以让LLM帮我们提取出“问题描述”和“解决方案”。(defun extract-qa-from-text (text model) \从一段文本中提取出可能的问题Q和答案A对。\ (let ((prompt (format nil \请分析以下Common Lisp相关的文本识别出其中提出的问题Q和给出的解决方案或答案A。请以JSON格式输出一个列表每个元素是一个对象包含question和answer两个字段。如果某部分只是讨论没有明确问答请忽略。~%~%文本~a~%~%只输出JSON不要有其他内容。\ text))) (let ((response (generate-chat-completion model (list (make-chat-message :role \user\ :content prompt)) :temperature 0.1))) ; 极低温度确保JSON格式严格 ;; 这里假设LLM返回的是合法的JSON字符串 (jonathan:parse response))))这其实就是简化版的RAG检索增强生成中的“提取”步骤。你可以将提取出的QA对存入数据库后续就可以构建一个简单的知识库问答系统。Lisp强大的符号处理和数据结构能力使得处理这种转换后的数据非常自然。5. 常见问题、调试技巧与性能优化在实际集成过程中你肯定会遇到各种问题。下面是我踩过的一些坑和总结的经验。5.1 网络与认证问题问题dex:http-request-failed错误状态码 401 (Unauthorized)。排查检查API密钥确保环境变量OPENAI_API_KEY已设置且正确。在REPL里执行(uiop:getenv \OPENAI_API_KEY\)看看是否返回预期值。检查密钥格式OpenAI的密钥通常以sk-开头。确保没有多余的空格或换行符。检查请求头确认Authorization头的格式是Bearer your-api-key。技巧可以写一个简单的测试函数只发送一个最小的请求比如用dex:get调用一个不需要认证的端点先确保网络连通性和Dexador配置正确。5.2 JSON解析错误问题jonathan:parse失败提示JSON格式无效。排查打印原始响应在调用jonathan:parse之前先用(format t \~a\ body)打印出响应的原始字符串。很可能API返回的不是JSON而是一个HTML错误页面比如Nginx的502错误。检查编码确保响应体是UTF-8编码。虽然现代API基本都是但以防万一。Dexador通常会处理好。流式响应误判如果你意外地将:want-stream设为t但试图解析返回的流stream对象为JSON就会失败。流需要按SSE格式读取。技巧使用handler-case包裹JSON解析代码在出错时打印出有问题的字符串片段便于诊断。5.3 流式响应处理处理OpenAI的流式响应stream: true是另一个挑战。它返回的是text/event-stream格式的数据不是单个JSON。(defun call-openai-streaming (prompt model) (let* ((url \https://api.openai.com/v1/chat/completions\) (headers ...) ; 同上 (data (jonathan:to-json (:model ,(model-name model) :messages ((:role \user\ :content ,prompt)) :stream t))) (stream (dex:post url :headers headers :content data :want-stream t))) (unwind-protect (loop for line (read-line stream nil nil) while line do (when (and ( (length line) 6) (string \data: \ line :end2 6)) (let ((data-str (subseq line 6)))) (unless (string>

相关新闻

Angry IP Scanner终极指南:3小时从入门到精通网络扫描配置

Angry IP Scanner终极指南:3小时从入门到精通网络扫描配置

Angry IP Scanner终极指南:3小时从入门到精通网络扫描配置 【免费下载链接】ipscan Angry IP Scanner - fast and friendly network scanner 项目地址: https://gitcode.com/gh_mirrors/ip/ipscan Angry IP Scanner是一款功能强大且用户友好的开源网络扫描工…

2026/10/17 8:08:55 阅读更多 →
从零开发AB PLC通信协议:CIP/PCCC协议解析与Python实战

从零开发AB PLC通信协议:CIP/PCCC协议解析与Python实战

1. 项目缘起:为什么需要自己动手搞AB PLC协议? 在工业自动化这个行当里,AB(Allen-Bradley)的PLC(可编程逻辑控制器)就像车间里的“大脑”,地位举足轻重。但很多时候,我们…

2026/10/17 8:09:13 阅读更多 →
ShardingSphere分布式数据库中间件架构与实战解析

ShardingSphere分布式数据库中间件架构与实战解析

1. ShardingSphere 核心架构解析 这个分布式数据库中间件生态圈正在重塑企业级数据架构。作为Apache顶级项目,ShardingSphere通过可插拔架构实现了数据库增量能力的扩展,其核心设计理念是将分片、读写分离、数据加密等能力从业务代码中彻底解耦。我在金融…

2026/10/17 8:12:57 阅读更多 →

最新新闻

JsLeakWatcher 报出一批对象,真的是内存泄漏吗:页面缓存、监听器和可达路径怎么分

JsLeakWatcher 报出一批对象,真的是内存泄漏吗:页面缓存、监听器和可达路径怎么分

JsLeakWatcher 报出一批对象,真的是内存泄漏吗:页面缓存、监听器和可达路径怎么分 页面退出后 JsLeakWatcher 报出几十个对象,团队立刻把所有缓存清掉,结果二次进入变慢,告警却仍然存在。工具发现“对象仍可达”&…

2026/10/18 15:00:54 阅读更多 →
Aspose.Slides 25.5 JDK 16 集成指南:License校验与模块化配置

Aspose.Slides 25.5 JDK 16 集成指南:License校验与模块化配置

简介:本资源是面向Java开发者的企业级PowerPoint文档处理解决方案,适用于需在Spring Boot、Servlet等后台架构中实现PPT/PPTX自动化生成、格式转换与深度编辑的中高级开发场景。压缩包共2个文件(1个JAR组件 1个XML许可证)&#x…

2026/10/18 15:00:54 阅读更多 →
2026批量查快递轨迹用什么工具好:从预算成本看,小中大团队各自该花多少钱

2026批量查快递轨迹用什么工具好:从预算成本看,小中大团队各自该花多少钱

先说结论:批量查快递轨迹这件事,预算从48元/天到1288元/年,覆盖了所有规模的团队。关键不是花多少钱,是花的钱能不能对应上你的业务规模。下面用需求对照矩阵,把不同预算档位该匹配什么业务量讲清楚。固乔快递批量查询…

2026/10/18 15:00:54 阅读更多 →
CentOS 8.2 手动编译 libssh 0.9.5 完整指南:独立安装与版本共存

CentOS 8.2 手动编译 libssh 0.9.5 完整指南:独立安装与版本共存

1. 为什么在 CentOS 8.2 上要手动编译 libssh 0.9.5CentOS 8.2 自带的 libssh 版本是 0.9.4,这个版本在功能上其实已经能满足大部分基础场景,比如简单的 SSH 客户端连接、SFTP 文件传输等。但如果你正在做安全审计、渗透测试工具链搭建,或者需…

2026/10/18 15:00:54 阅读更多 →
Linux 开发工具(三) 深入理解编译器: gcc / g++

Linux 开发工具(三) 深入理解编译器: gcc / g++

目录 一. 编译的四个阶段 1.1 预处理 1.1.1 代码示例 1.1.2 命令行宏定义 1.1.3 条件编译的用处 1.2 编译 1.2.1 代码示例 1.3 汇编 1.3.1 代码示例 1.4 链接 1.4.1 代码示例 二. 动态库和静态库 2.1 什么是库 2.2 库文件的命名规则 2.3 动静态库 2.4 动态链接…

2026/10/18 15:00:54 阅读更多 →
对话工具升级为生成式界面引擎:免费开放与交互范式切换

对话工具升级为生成式界面引擎:免费开放与交互范式切换

1. 这次升级到底改了什么:从“对话工具”到“生成式界面引擎”先把结论摆在前面:这次更新的核心不是“模型又聪明了一点”,而是交互范式的切换。过去的对话产品,本质上是一个文本进、文本出的黑盒,你问它答&#xff0c…

2026/10/18 14:59:53 阅读更多 →

日新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/18 0:00:55 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/18 0:00:55 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/18 0:00:55 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/18 0:00:55 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/18 0:00:55 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/18 0:00:55 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/18 0:55:02 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/17 17:22:31 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/18 12:16:16 阅读更多 →