WWW.YOUINFO.SITE
标签聚合 代码

/tag/代码

LinuxDo 最新话题 · 2026-06-11 22:42:04+08:00 · tech

本帖使用社区开源推广,符合推广要求。我申明并遵循社区要求的以下内容: 我的帖子已经打上 开源推广 标签: 是 我的开源项目完整开源,无未开源部分: 是 我的开源项目已链接认可 LINUX DO 社区: 是 我帖子内的项目介绍,AI生成、润色内容部分已截图发出: 是 以上选择我承诺是永久有效的,接受社区和佬友监督: 是 以下为项目介绍正文内容,AI生成、润色内容已使用截图方式发出 前言 本教程的环境基于 jdk8 + langchain4j 0.35 教程源码放在这里了: github.com GitHub - worenbudaoni/rag-study-helper: 一个学习检索增强生成的全流程助手 一个学习检索增强生成的全流程助手 文章内容 因为内容比较多,我会从下面三个文章进行讲解,后续发布后会贴出来,这节讲: 接入飞书WIKI文档 RAG实现全流程 : 【开源、教程】RAG全流程实现(java+完整代码):第一弹 接入飞书WIKI文档 接口限流:令牌桶 + AOP 强烈建议先看完第一弹,不然后面代码有可能看不懂 实现逻辑 后面会有图文讲解的,这里就相当于大概介绍一下,看个大概就好,有不了解的不要先去搜,我后文都会讲,如果讲漏了麻烦评论一下,我改正 飞书开发者平台 : 1、去飞书开发者平台创建一个应用 2、给应用赋予权限(权限管理 菜单) 3、给应用赋予机器人能力(添加应用能力 菜单) 4、发布(版本管理与发布 菜单) 5、获取应用的app-id、app-secret(凭证和基础信息 菜单) 飞书app : 1、创建一个群聊 2、把机器人给拉进去 3、点击左边菜单的更多找到知识库,新建知识库(下面统一称为 WIKI) 4、添加群聊(机器人)为管理员:点 WIKI 进去会打开一个网站,左下角有个设置点进去,在成员设置->角色与权限->管理员,添加管理员,搜索我们刚才创建的有机器人的群聊并添加 5、在页面的连接处找到space-id,如: https://kcnvw23rzo5r.feishu.cn/wiki/settings/666666(666666就是我们要的space-id) 项目 : 1、创建一个job,用来定时获取文档(下面为job启动后的流程) 2、通过app-id、app-secret获取tenant_access_token和expire 3、通过tenant_access_token和space-id获取文档信息(名字、更新时间、documentToken 等等) 4、通过documentToken去获取文档的内容(字符串) 5、走 【开源、教程】RAG全流程实现(java+完整代码):第一弹 的入库流程 一、飞书开发者平台 app-id、app-secret 是啥 app-id :应用的唯一标识 app-secret :应用的密钥,在创建应用时由平台生成,可用于获取app_access_token 1、飞书开放平台创建企业应用 开发者后台 - 飞书开放平台 这里注意的是创建好应用后需要审核、启用,所以企业级的应用权限在领导手上,我们可以创建一个个人版的飞书账号来做实验 2、给应用赋予权限 (权限管理菜单) 直接复制我的也行 { "scopes": { "tenant": [ "bitable:app:readonly", "docx:document:readonly", "drive:drive:readonly", "drive:file:readonly", "wiki:wiki:readonly" ], "user": [] } } 3、给应用赋予机器人能力 (添加应用能力菜单) 4、发布 (版本管理与发布菜单) 创建好后发布就行 5、获取应用的app-id、app-secret(凭证和基础信息菜单) 二、飞书app space-id是啥 就是飞书知识库(WIKI)所对应的空间ID,我们找到这个空间就可以找到下面的文档 打个比方就是图书馆的书架,书架有个唯一标识(小说),我们根据这个书架ID(小说)去找下面所有的书 1、创建一个群聊 2、把机器人给拉进去 3、点击左边菜单的更多找到知识库,新建知识库(下面统一称为 WIKI) 4、添加群聊(机器人)为管理员 点 WIKI 进去会打开一个网站,左下角有个设置点进去,在成员设置->角色与权限->管理员,添加管理员,搜索我们刚才创建的有机器人的群聊并添加 5、在页面的连接处找到space-id 如: https://kcnvw23rzo5r.feishu.cn/wiki/settings/666666(666666就是我们要的space-id) 三、项目 这里就不按照上面实现逻辑写的走了,我就按照代码里的讲解 1、job总览(步骤拆解在后面) FeishuSyncService.java // 没想加重框架,如果用xxl-job什么的,自己搬一下就行了 @Scheduled(cron = "${app.feishu.cron}") public void syncWiki() { log.info("Starting Feishu wiki sync for space: {}", spaceId); try { // 获取全部文档信息(通过app-id、app-secret、space-id) // 这里逻辑后面会讲 List<WikiNode> nodes = feishuClient.getWikiNodeTree(spaceId); log.info("Found {} nodes in wiki", nodes.size()); // 成功数量,跳过数量(如果数据存在了关系型数据库且没有更新就跳过),失败数量 int synced = 0, skipped = 0, failed = 0; for (WikiNode node : nodes) { // 后缀 String objType = node.getObjType(); // 文档令牌 用来获取 文档内容 String nodeToken = node.getNodeToken(); // 更新时间判断是否需要跳过 long updateTime = node.getUpdateTime(); // 是否入库 Documents doc = documentsMapper.selectOne( Wrappers.<Documents>lambdaQuery() .eq(Documents::getFeishuNodeToken, nodeToken) ); // 文档是否更新是否需要跳过,这个更新时间不在where条件里面是因为后续要继续用到这个数据 if (doc != null && doc.getFeishuUpdateTime() != null && doc.getFeishuUpdateTime() == updateTime) { skipped++; continue; } try { // 文档内容 String content; // 获取文件名 String fileName; switch (objType) { case "doc": case "docx": // 获取文档内容 // 这里逻辑就不讲了,我后面扔给飞书的文档,照着对接或者看我源码就好 content = feishuClient.getDocumentContent(node.getObjToken()); fileName = node.getNodeTitle() + "_文档"; break; case "sheet": content = feishuClient.getSheetContent(node.getObjToken()); fileName = node.getNodeTitle() + "_表格"; break; case "bitable": content = feishuClient.getBitableContent(node.getObjToken()); fileName = node.getNodeTitle() + "_多维表格"; break; default: skipped++; continue; } // 如果是更新,先删旧向量和映射记录 if (doc != null) { // 查询旧文档相关的向量映射 List<DocumentChunks> oldChunks = documentChunksMapper.selectList( Wrappers.<DocumentChunks>lambdaQuery() .eq(DocumentChunks::getDocumentId, doc.getId()) ); // 有两张表 // 第一张为文档库:记录文档标题、更新时间、创建人等信息 // 第二张为分片库:记录向量数据库插入后的向量ID // 向量ID List<String> vectorIds = oldChunks.stream() .map(DocumentChunks::getVectorId) .collect(Collectors.toList()); // 删除向量 embeddingStore.removeAll(vectorIds); // 删除映射记录 documentChunksMapper.delete( Wrappers.<DocumentChunks>lambdaQuery() .eq(DocumentChunks::getDocumentId, doc.getId()) ); // 删除文档 documentsMapper.deleteById(doc.getId()); } // RAG 入库流程 (第一篇文章中亦有记载(跟第一章代码有些许出入,看完第一章后,直接看源码更佳)) ingestionService.ingestFeishuDocument(fileName, content, nodeToken, updateTime, objType); synced++; log.info(" Synced: {} ({})", node.getNodeTitle(), nodeToken); } catch (Exception e) { log.error(" Failed to sync node: {} ({})", node.getNodeTitle(), nodeToken, e); failed++; } } // 清理远程已删除的文档 // 这里的逻辑是 // 第一次job执行:查询飞书wiki给了 A、B、C 三个文档入库 // 后面有人在wiki中删了 C 文档 // 第二次job执行:只有查询出 A、B 两个文档 // 这时就要去数据库中和向量库中删除多余的 C 文档 List<String> remoteTokens = nodes.stream() .map(WikiNode::getNodeToken) .collect(Collectors.toList()); if (!remoteTokens.isEmpty()) { // MySQL 查出本地多出的记录,只遍历需要删除的 List<Documents> toRemove = documentsMapper.selectList( Wrappers.<Documents>lambdaQuery() .isNotNull(Documents::getFeishuNodeToken) .notIn(Documents::getFeishuNodeToken, remoteTokens) ); for (Documents removed : toRemove) { log.info("Document removed remotely, cleaning up: {} ({})", removed.getDocumentName(), removed.getFeishuNodeToken()); List<DocumentChunks> chunks = documentChunksMapper.selectList( Wrappers.<DocumentChunks>lambdaQuery() .eq(DocumentChunks::getDocumentId, removed.getId()) ); List<String> vectorIds = chunks.stream() .map(DocumentChunks::getVectorId) .collect(Collectors.toList()); // 向量数据库 删 embeddingStore.removeAll(vectorIds); // 关系型数据库 分片库 删 documentChunksMapper.delete( Wrappers.<DocumentChunks>lambdaQuery() .eq(DocumentChunks::getDocumentId, removed.getId()) ); // 关系型数据库 文档库 删 documentsMapper.deleteById(removed.getId()); } } log.info("Feishu wiki sync complete: synced={}, skipped={}, failed={}", synced, skipped, failed); } catch (Exception e) { log.error("Feishu wiki sync failed", e); } } 2、递归获取知识库所有文档节点 FeishuClient.java 这里其实没什么特别好讲的点,就是参考飞书文档,然后请求并解析 我在源码里也标记了文档的地址,所以这里放一个总体的查询地址 开发文档 - 飞书开放平台 /** * 获取 tenant_access_token(内部自动缓存和刷新) */ public synchronized String getAccessToken() throws IOException { if (cachedToken != null && System.currentTimeMillis() < tokenExpireAt) { return cachedToken; } String json = "{\"app_id\":\"" + appId + "\",\"app_secret\":\"" + appSecret + "\"}"; // https://open.feishu.cn/document/server-docs/authentication-management/access-token/tenant_access_token_internal Request request = new Request.Builder() .url(baseUrl + "/open-apis/auth/v3/tenant_access_token/internal") .post(RequestBody.create(JSON, json)) .build(); try (Response resp = httpClient.newCall(request).execute()) { JsonNode body = objectMapper.readTree(resp.body().string()); if (body.get("code").asInt() != 0) { throw new IOException("Failed to get access token: " + body); } cachedToken = body.get("tenant_access_token").asText(); // tenant_access_token 的最大有效期是 2 小时 // 7200 是秒 int expire = body.get("expire").asInt(7200); // 防御性编程 免得刚好过期 由于网络延时 造成接口调用失败 tokenExpireAt = System.currentTimeMillis() + (expire - 60) * 1000L; return cachedToken; } } /** * 递归获取知识库所有文档节点。 */ public List<WikiNode> getWikiNodeTree(String spaceId) throws IOException { List<WikiNode> allNodes = new ArrayList<>(); collectNodes(spaceId, null, allNodes); return allNodes; } private void collectNodes(String spaceId, String parentNodeToken, List<WikiNode> result) throws IOException { List<WikiNode> currentLevelNodes = new ArrayList<>(); String pageToken = null; do { // https://open.feishu.cn/document/server-docs/docs/wiki-v2/space-node/create StringBuilder url = new StringBuilder(baseUrl + "/open-apis/wiki/v2/spaces/" + spaceId + "/nodes"); if (parentNodeToken != null) { url.append("/").append(parentNodeToken).append("/children"); } url.append("?page_size=50"); if (pageToken != null) { url.append("&page_token=").append(pageToken); } Request request = new Request.Builder() .url(url.toString()) .header("Authorization", "Bearer " + getAccessToken()) .get() .build(); try (Response resp = httpClient.newCall(request).execute()) { JsonNode body = objectMapper.readTree(resp.body().string()); if (body.get("code").asInt() != 0) { log.error("Wiki API error for URL [{}]: {}", url, body); break; } JsonNode items = body.path("data").path("items"); for (JsonNode item : items) { WikiNode node = new WikiNode(); // 节点token node.setNodeToken(item.path("node_token").asText()); // 对应文档类型的token,可根据 obj_type 判断属于哪种文档类型。 node.setObjToken(item.path("obj_token").asText()); // 文档类型,对于快捷方式,该字段是对应的实体的obj_type。 // 可选值有: // doc:旧版文档 sheet:表格 mindnote:思维导图 bitable:多维表格 file:文件 docx:新版文档 slides:幻灯片 node.setObjType(item.path("obj_type").asText()); // 文档标题 node.setNodeTitle(item.path("title").asText()); node.setParentNodeToken(parentNodeToken); // 是否有子节点 node.setHasChild(item.path("has_child").asBoolean(false)); // 文档最近编辑时间 String editTime = item.path("obj_edit_time").asText(); node.setUpdateTime(Long.parseLong(editTime.isEmpty() ? "0" : editTime)); currentLevelNodes.add(node); } pageToken = body.path("data").path("page_token").asText(null); } } while (pageToken != null && !pageToken.isEmpty()); // Add all nodes from this level, then recurse into children result.addAll(currentLevelNodes); for (WikiNode node : currentLevelNodes) { if (node.isHasChild()) { collectNodes(spaceId, node.getNodeToken(), result); } } } 四、测试 1、导入文档 还是拿这个 补鸡稻 作为测试案例 2、配置 app-id、app-secret、space-id和sync-enable 我这里通过 jvm 运行参数注入,免得又把 apikey 给上传到 github 了 sync-enable 记得为 true,不然不注册 spring bean 3、运行时发现文档可以查询到,并且入库了 4、提问 5、测试结束,完结撒花 1 个帖子 - 1 位参与者 阅读完整话题

LinuxDo 最新话题 · 2026-06-11 21:51:47+08:00 · tech

我让它分析一些跨国和(毛子)商业博弈问题,直接告诉我危险行为,降级到opus4.8。 难道是因为中国和俄罗斯敏感肌了? 我都没问法律被告辩护相关问题,比如减罪这种岂不是一句话都说不了? 我猜测涉及服务器的也不行?(哪怕是自己的服务器),昨天进行市场分析没有降级,但市场分析其实其他模型一样能做好,这样Table5实用性就大大下降了。 在CC里面似乎看不到记录,附new api证据,来回切的我都烦了, 1 个帖子 - 1 位参与者 阅读完整话题

LinuxDo 最新话题 · 2026-06-11 21:14:11+08:00 · tech

如果都用现成代码训练大语言模型的话,那是不是以后各种语言、框架和库的模式和规约就只能定死不能改变了,比如我熟悉的前端 React 本来 hook 不是主流的,但是后面都用 hook 了,但是如果大语言模型在 hook 之前推出的话,那么生成的代码大概率是按照之前的规范来写的。 我现在写 python 也会发现这样的问题,很多时候大语言生成的是能运行但是并非当前最佳实践的写法,有时候甚至会混着用不同的模式,如果以后都是 vibe coding 那么代码质量是会越来越好还是越来越拉似乎值得深思,即使训练时候严格控制训练集代码也无法解决这样的问题… 4 个帖子 - 2 位参与者 阅读完整话题

LinuxDo 最新话题 · 2026-06-11 15:41:32+08:00 · tech

前言 前面我们实现了一个 配合xray内核 reality协议 的 极简翻墙客户端(壳) MDPC-my-dream-proxy-client 如果我们想 配合 Hysteria 内核呢? (只为了简单演示, 所以只处理自签证书的情况) 分析 根据my-dream-proxy-client项目(下称MDPC)的设计, MDPC的配置文件参数为: listen: port: files-dir: core-start: core-test: log: 我们可以填上 hy2 对应的信息, 如: listen: "127.0.0.1" port: "18180" files-dir: "./bin/hy2/" core-start: "bin/hy2/hysteria client -c bin/hy2/config.yaml" core-test: "" log: "" 这样后端就好了. 是不是很简单! 接下来就是创造前端的HTML, 用来生成hy2客户端配置文件的yaml文本 可以先从简单的YAML文本编辑框作为基础功能. 然后再加表单. 开发过程 hermes 对接 mimo-v2.5-pro 基于 极简翻墙客户端(壳) 开发 配合 Hysteria 内核 支持Hysteria2协议 自签证书指定证书指纹pinSHA256 Github G站/crazypeace/my-dream-proxy-client 使用方法 见项目 README.md G站/crazypeace/my-dream-proxy-client/blob/main/README.md#my-dream-proxy-client-使用手册-配合hysteria内核 ======== 后记 本次开发由 hermes 对接 mimo-v2.5-pro 1 个帖子 - 1 位参与者 阅读完整话题

v2ex · 2026-06-11 11:02:21+08:00 · tech

最近对 AI 辅助编程挺感兴趣的,想看看在几乎全靠 Codex 辅助的情况下,能以多快的速度跑通一个完整的 Web 项目。为了找个现成的逻辑来练手,我就复刻了一个经典的测试小工具:8values 。 🔗 练手项目地址: https://8value.online/ 🛠️ 开发体验 & 感受: 整个项目基本是抱着 Codex 的大腿写出来的。体验下来感觉非常有意思: 逻辑生成: 像这种“几十道题、计算分值、映射到 4 个不同维度(经济、外交、公民、社会)并匹配最终结果”的逻辑,用自然语言描述给 Codex 后,它给出的代码骨架非常完整,省去了很多敲 boilerplate 代码的时间。 样式微调: 前端 UI 主要也是让 AI 帮忙生成的,然后我自己微调了进度条的动效和移动端的适配。有时候 AI 会在 CSS 上犯点小迷糊,但通过多轮 Prompt 纠正,基本都能搞定。 整体感受: 作为练手项目,AI 确实极大降低了“造轮子”的摩擦力,感觉以后验证一些小想法会越来越快。 📌 关于 8values 测试本身: 如果不了解 8values 的 V 友,简单科普一下:这是一个通过回答几十道情境题,来测算你个人在“经济、外交、公民、社会”四个维度的倾向,并最终给你打上一个“意识形态标签”(比如古典自由主义、社会民主主义等)的测试。 大家平时可能觉得自己是“中立”的,用这个数据化的小工具照照镜子还挺好玩。 ⚠️ 叠个甲(防杠补丁): 这就是个拿来练手编程的项目,测试题目和模型本身也是网上开源的经典版本。大家点进去测着图一乐就好,看看结果准不准。千万别在评论区过度键政哈,保护账号,Peace & Love 🐶 欢迎大家来测测看,也欢迎从技术或前端体验的角度提提建议(比如哪里有 Bug 、移动端排版等),我再去让 Codex 帮忙修一下,哈哈。

LinuxDo 最新话题 · 2026-06-11 10:26:20+08:00 · tech

1.用管理员身份打开 Windows PowerShell 输入代码,等待加载完成 Invoke-WebRequest "http://tlu.dl.delivery.mp.microsoft.com/filestreamingservice/files/f90c8266-7651-4aa0-a508-79555e3b74e5?P1=1781155129&P2=404&P3=2&P4=aEC7AAs4D%2bUWbPfXGqCJuUcFfbK3QWpC3qi3qpL25FQXKiqNEm061AkeQGjnTv5Wshfp1JZLnKsaJ1Y%2bFT55zA%3d%3d" -OutFile codex.msix 2.加载完成后回车再输入 Add-AppxPackage codex.msix 加载完成 就安装成功codex,直接本地搜 codex 就能出现 1 个帖子 - 1 位参与者 阅读完整话题

v2ex · 2026-06-11 10:15:58+08:00 · tech

最近对 AI 辅助编程挺感兴趣的,想看看在几乎全靠 Codex 辅助的情况下,能以多快的速度跑通一个完整的 Web 项目。为了找个现成的逻辑来练手,我就复刻了一个经典的测试小工具:8values 。 🔗 练手项目地址: https://8value.online/ 🛠️ 开发体验 & 感受: 整个项目基本是抱着 Codex 的大腿写出来的。体验下来感觉非常有意思: 逻辑生成: 像这种“几十道题、计算分值、映射到 4 个不同维度(经济、外交、公民、社会)并匹配最终结果”的逻辑,用自然语言描述给 Codex 后,它给出的代码骨架非常完整,省去了很多敲 boilerplate 代码的时间。 样式微调: 前端 UI 主要也是让 AI 帮忙生成的,然后我自己微调了进度条的动效和移动端的适配。有时候 AI 会在 CSS 上犯点小迷糊,但通过多轮 Prompt 纠正,基本都能搞定。 整体感受: 作为练手项目,AI 确实极大降低了“造轮子”的摩擦力,感觉以后验证一些小想法会越来越快。 📌 关于 8values 测试本身: 如果不了解 8values 的 V 友,简单科普一下:这是一个通过回答几十道情境题,来测算你个人在“经济、外交、公民、社会”四个维度的倾向,并最终给你打上一个“意识形态标签”(比如古典自由主义、社会民主主义等)的测试。 大家平时可能觉得自己是“中立”的,用这个数据化的小工具照照镜子还挺好玩。 ⚠️ 叠个甲(防杠补丁): 这就是个拿来练手编程的项目,测试题目和模型本身也是网上开源的经典版本。大家点进去测着图一乐就好,看看结果准不准。千万别在评论区过度键政哈,保护账号,Peace & Love 🐶 欢迎大家来测测看,也欢迎从技术或前端体验的角度提提建议(比如哪里有 Bug 、移动端排版等),我再去让 Codex 帮忙修一下,哈哈。