最近申请了appid和hash弄了一个爬虫的脚本插件做测试,就我一个人用按理来说是没什么问题的。然后今天早上收到了一次非telegram官方的消息,他给我发的信息是申请账号的使用我敢肯定我是被钓鱼了,我输入了验证码。然后我赶紧的开了账号安全锁和二步验证删除了所有已登录的设备,以及tg账号的密码。过了一会就被自动登出了,然后我再次尝试用手机号 邮箱登录就变成如图所示这样了。登不上去了,起初还需要1.45刀。是不是被风控了?求佬友们帮助 2 个帖子 - 2 位参与者 阅读完整话题
10 个帖子 - 7 位参与者 阅读完整话题
fofa大善人也不善,我常用的fid查询icon查询都无了,打野区的佬友们支支招吧!! 1 个帖子 - 1 位参与者 阅读完整话题
本帖使用社区开源推广,符合推广要求。我申明并遵循社区要求的以下内容: 我的帖子已经打上 开源推广 标签: 是 我的开源项目完整开源,无未开源部分: 是 我的开源项目已链接认可 LINUX DO 社区: 是 我帖子内的项目介绍,AI生成、润色内容部分已截图发出: 是 以上选择我承诺是永久有效的,接受社区和佬友监督: 是 以下为项目介绍正文内容,AI生成、润色内容已使用截图方式发出 AI ssh编辑远程文件的时候经常出错。 sed 需要转义正则, cat <<EOF 没有完整性校验——多数失败不是模型的问题,而是编辑工具的问题。 hline 通过为每行标注内容 hash 解决这个问题。用 hcat 查看,用 hsed 编辑。零依赖,单二进制,SSH 优先。 设计思路参考了 [oh-my-pi]和 [oh-my-openagent],感谢开源。 项目地址: hline/README-CN.md at main · chennest/hline 快速安装(Linux) # 国内加速(使用 ghfast 代理) curl -sL https://ghfast.top/https://github.com/chennest/hline/releases/latest/download/hline-linux-amd64.tar.gz | sudo tar xz -C /usr/local/bin 工作原理 hcat — 带 hash 锚点查看文件 每行标注 2 位字母 hash: $ hcat /etc/nginx/nginx.conf 5-10 5#VK| server { 6#XJ| listen 80; 7#MB| server_name example.com; 8#QR| root /var/www/html; 9#TN| } 10#WS| AI 读取输出后,通过 6#XJ 这样的锚点定位行进行编辑。hash 仅基于 行内容 计算——上方插入或删除行不会影响下方锚点。 hsed — 通过锚点编辑 三种操作: # 替换单行 hsed /etc/nginx/nginx.conf replace 6#XJ << 'EOF' listen 443 ssl; EOF # 替换范围 hsed /etc/nginx/nginx.conf replace 6#XJ 7#MB << 'EOF' listen 443 ssl; server_name new.example.com; EOF # 删除行(空内容) hsed /etc/nginx/nginx.conf replace 6#XJ 7#MB << 'EOF' EOF # 在行后插入 hsed /etc/nginx/nginx.conf append 9#TN << 'EOF' location /api { proxy_pass http://127.0.0.1:3000; } EOF # 在行前插入 hsed /etc/nginx/nginx.conf prepend 5#VK << 'EOF' # Managed by hline EOF Hash 校验 每次编辑时, hsed 会重新计算目标行的 hash: 匹配 → 执行编辑 不匹配 → 拒绝并显示当前状态: ERROR: hash mismatch at line 6 expected: 6#XJ current: 6#PM| listen 8080; AI 可以直接复制正确的锚点重试。 范围语法(hcat) hcat file.conf # 全文件 hcat file.conf 5-10 # 第 5-10 行 hcat file.conf 5 +10 # 从第 5 行起看 10 行 hcat file.conf 5 # 从第 5 行到末尾 hcat file.conf -A 3 5 # 第 5 行 + 后 3 行 hcat file.conf -B 2 -A 3 5 # 第 5 行 + 前 2 后 3 为什么需要 hline 问题 hline 解决方案 sed 正则转义噩梦 通过 hash 字面量匹配内容 AI 无法验证文件状态 hash 校验内容未变更 多次编辑竞态条件 每个锚点自带完整性检查 服务器无需额外框架 单二进制,SSH 优先设计 1 个帖子 - 1 位参与者 阅读完整话题
Rust 实现 ReAct 和主循环 use std::{ collections::HashMap, io::{self, Write}, }; use async_openai::types::chat::{ ChatCompletionMessageToolCalls, ChatCompletionRequestAssistantMessage, ChatCompletionRequestAssistantMessageArgs, ChatCompletionRequestMessage, ChatCompletionRequestSystemMessage, ChatCompletionRequestToolMessage, ChatCompletionRequestUserMessage, ChatCompletionResponseMessage, ChatCompletionTool, ChatCompletionToolChoiceOption, CreateChatCompletionRequestArgs, FunctionObjectArgs, ToolChoiceOptions, }; use async_openai::{Client, config::OpenAIConfig}; use serde_json::{Value, json}; use tokio::io::{AsyncBufReadExt, BufReader}; const MODEL: &str = "gpt-5.4-mini"; type ToolFn = fn(&str) -> String; #[tokio::main] async fn main() -> Result<(), anyhow::Error> { let mut agent = ReActAgent::new().await?; agent.chat_loop().await } struct ReActAgent { pub client: Client<OpenAIConfig>, pub messages: Vec<ChatCompletionRequestMessage>, pub tool: ChatCompletionTool, pub available_tools: HashMap<&'static str, ToolFn>, } impl ReActAgent { async fn new() -> Result<Self, anyhow::Error> { dotenvy::dotenv().ok(); let client = Client::new(); let messages = vec![ChatCompletionRequestSystemMessage::from("你是一个强大的聊天机器人,请根据用户的提问进行答复,如果需要调用工具请直接调用,不知道请直接回复不清楚").into()]; let tool = ChatCompletionTool { function: FunctionObjectArgs::default().name("calculator").description("一个可以计算数学表达式的计算器").parameters(json!({ "type":"object", "properties": {"expression":{"type":"string","description":"需要计算的数学表达式,例如:'123+456+789'"}}, "required":["expression"], "additionalProperties": false })) .strict(true) .build()?, }; Ok(Self { client, messages, tool, available_tools: HashMap::from([("calculator", calculator as ToolFn)]), }) } async fn process_query(&mut self, query: &str) -> Result<String, anyhow::Error> { // 处理用户输入 self.messages .push(ChatCompletionRequestUserMessage::from(query).into()); let response_message = self.create_chat_completion(None).await?; // 判断是否执行工具调用 if let Some(tool_calls) = response_message .tool_calls .clone() .filter(|calls| !calls.is_empty()) { // 将模型第一次工具调用回复添加到历史消息中 self.messages.push( ChatCompletionRequestAssistantMessageArgs::default() .tool_calls(tool_calls.clone()) .build()? .into(), ); for tool_call in tool_calls { let ChatCompletionMessageToolCalls::Function(tool_call) = tool_call else { continue; }; let tool_name = tool_call.function.name.as_str(); let tool_args: Value = tool_call.function.arguments.parse()?; let expression = tool_args["expression"].as_str().unwrap_or_default(); let function_to_call = self .available_tools .get(tool_name) .ok_or_else(|| anyhow::anyhow!("未知工具: {tool_name}"))?; let result = function_to_call(expression); println!("Tool Call: {tool_name}"); println!("Tool [{tool_name}] Result: {result}"); // 将工具结果添加到历史消息中 self.messages.push( ChatCompletionRequestToolMessage { content: result.into(), tool_call_id: tool_call.id, } .into(), ); } // 再次调用模型,让它基于工具调用的结果生成最终回复内容 let second_response_message = self .create_chat_completion(Some(ChatCompletionToolChoiceOption::Mode( ToolChoiceOptions::None, ))) .await?; let content = second_response_message.content.clone().unwrap_or_default(); self.messages .push(ChatCompletionRequestAssistantMessage::from(content.clone()).into()); return Ok(format!("Assistant: {content}")); } let content = response_message.content.unwrap_or_default(); self.messages .push(ChatCompletionRequestAssistantMessage::from(content.clone()).into()); Ok(format!("Assistant: {content}")) } async fn create_chat_completion( &self, tool_choice: Option<ChatCompletionToolChoiceOption>, ) -> Result<ChatCompletionResponseMessage, anyhow::Error> { let mut request = CreateChatCompletionRequestArgs::default(); request .model(MODEL) .messages(self.messages.clone()) .tools(self.tool.clone()); if let Some(tool_choice) = tool_choice { request.tool_choice(tool_choice); } let response = self.client.chat().create(request.build()?).await?; response .choices .first() .map(|choice| choice.message.clone()) .ok_or_else(|| anyhow::anyhow!("模型没有返回可用回复")) } /// 交互式 REPL 循环;输入 `quit` 退出。 async fn chat_loop(&mut self) -> Result<(), anyhow::Error> { // 异步读取标准输入,避免阻塞 tokio 运行时 let stdin = tokio::io::stdin(); let mut reader = BufReader::new(stdin); loop { print!("\nQuery: "); // 立即刷新提示符,保证在等待输入前可见 io::stdout().flush().ok(); // 部分 IDE 控制台可能传入非 UTF-8 字节,按字节读取可以避免 REPL 直接退出。 let mut line = Vec::new(); if reader.read_until(b'\n', &mut line).await? == 0 { break; } let query = String::from_utf8_lossy(&line); let query = query.trim(); if query.is_empty() { continue; } if query.eq_ignore_ascii_case("quit") { break; } // 单轮出错不应中断整个会话,只打印错误信息继续下一轮 match self.process_query(query).await { Ok(resp) => println!("{resp}"), Err(e) => eprintln!("\nError: {e:#}"), } } Ok(()) } } fn calculator(expression: &str) -> String { match fasteval::ez_eval(expression, &mut fasteval::EmptyNamespace) { Ok(result) if result.is_finite() => json!({"result": result}).to_string(), Ok(_) => json!({"error": "无效表达式, 错误信息: 结果不是有限数字"}).to_string(), Err(error) => json!({"error": format!("无效表达式, 错误信息: {error}")}).to_string(), } } 1 个帖子 - 1 位参与者 阅读完整话题
Mitchell Hashimoto – 28 Apr 26 Ghostty Is Leaving GitHub 主要原因:GitHub近期的稳定性和可靠性实在是太差了 Mitchell这位大牛真正的开了这个头,后续大概率会有更多项目迁移出去 14 个帖子 - 8 位参与者 阅读完整话题