慣性聚合 高效追讀感興趣之博客、新聞、科技資訊
閱原文 以慣性聚合開啟

推薦訂閱源

博客园 - 司徒正美
V
V2EX
T
Tailwind CSS Blog
有赞技术团队
有赞技术团队
aimingoo的专栏
aimingoo的专栏
Apple Machine Learning Research
Apple Machine Learning Research
IT之家
IT之家
Blog — PlanetScale
Blog — PlanetScale
A
About on SuperTechFans
月光博客
月光博客
T
The Blog of Author Tim Ferriss
宝玉的分享
宝玉的分享
Martin Fowler
Martin Fowler
博客园 - 聂微东
The GitHub Blog
The GitHub Blog
V
Visual Studio Blog
WordPress大学
WordPress大学
酷 壳 – CoolShell
酷 壳 – CoolShell
Engineering at Meta
Engineering at Meta
GbyAI
GbyAI

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant Common SOC 2 Failures (Real World) Stop Vibe-Checking Your AI App: A Practical Guide to Evals How to Use SonarQube and SonarScanner Locally to Level Up Your Code Quality Your Next To-Do App Is Dead — I Replaced Mine with an OpenClaw AI Sign a Nostr event in 60 lines of Python using coincurve — no nostr-sdk, no nbxplorer, no rust toolchain ITGC Audit Explained Like You’re in Big 4 Patch Tuesday abril 2026: Microsoft parcha 163 vulnerabilidades y un zero-day en SharePoint Stop scraping everything: a better way to track competitor price changes Listing on MCPize + the Official MCP Registry while routing payments OUTSIDE the marketplace — how I kept 100% of my x402 revenue Building an AI-Powered Risk Intelligence System Using Serverless Architecture Why We Ripped Function Overloading Out of Our AI Toolchain Testing AI-Generated Code: How to Actually Know If It Works SaaS Churn Is Killing Your Business. Here Is What to Do About It (Without a Support Team) The Speed of AI Is No Longer Linear - And Self-Improving Models Are Why How to Implement RBAC for MCP Tools: A Practical Guide for Engineering Teams From Standard Quote to Persuasive Proposal: AI Automation for Arborists I built a CLI that scaffolds complete multi-tenant SaaS apps Axios CVE-2025–62718: The Silent SSRF Bug That Could Be Hiding in Your Node.js App Right Now The dashboard that ended our friendship Data Pipelines Explained Simply (and How to Build Them with Python)
《滂沱者说》
Connor Green · 2026-05-24 · via DEV Community

A lobster standing on the bottom of the ocean with its claws raised as it looks at the camra

此乃投于Gemma 4之赛:论Gemma 4

Gemma 4者,究为何物?简言之,乃开放权重、开源之AI模型,为推演、编程、及复杂代理工作流而建。

盖其出于阿帕奇二版之许,入其门者几无障也。汝可易其重,商用之,尤要者,可于本地行之。此使开发者得高端大语言模型之权,而无所费于专器或第三方API之订也。

然真之奇术,乃在配以Gemma 4与Google之代理开发套件(ADK)。此框架使汝得自简朴之问应循环,进至构建、调试、且大规模部署可靠之智能代理。

"Agent"何意?

智能体者,自主感知其境,审决而为之行,以达一特定之目者也。于智能体之域,应用大略有三:

  • 简易反射体:循当前之状,依"若然则然"之理。
  • 目标体: 乃设策以应远图,若预订休沐之游。
  • 学而进者: 时日既久,渐悟于反饷。

自动化贷款审批,抑或侦测网络行为之异常,若需应用程序自主行事,仿若人类之思辨,则需一智能体。此挑战中,吾之目标乃验一由Gemma 4驱动之智能体,能否于社交网络中,为谬误信息担任仲裁。

入细论之前,若君寻活体原型至此,当已觉此帖乃"文呈",非"制呈"。故不幸,吾无炫目之示。今但分吾筑误信侦察之助,用Gemma 4与Google Agent Development Kit时所得之构架之训。欲及代码,先当回视,察社交网络中误信之患。

谎言之速

有古谚云: “谎言之行,半世已遍,而真言之履犹未成。”

当此社交媒体之世,此非复比喻。欺诳今得算法之助,有"群演"(机器人及协同之"影响者"账号)为之助势,使虚妄似为可信。欲制此,当止视之为竞逐之简单,当察此失实之网络实如何构筑。此网络之建,大抵分两阶段.

第一阶段:无邪之渐积

事初常隐微。或立户名,若“日日萌兽图”,或“忙碌妈妈之基督梗”

  1. 速获千众:户名立时,立得万千追随者(多系木偶)。
  2. “互粉”之惑: 乃随数千无名之辈,其中多因习俗而互随者。
  3. 互动之机: 此号所出,皆AI所造之文,专为迎合平台算法及风气,以求高互动。

其二阶段:转向"病原体"。

网既广,则文移矣。无伤之帖转为争端。假智械之叙事,网始诋信息,扬虚妄,或造无争之辩象。因群虱之网速传此文,众“赞”与“传”使有机者信之。彼传诸友,友复传之,倏忽,前所讥为荒诞之见或不可及之论,竟成流俗。

重构其解:入斯洛普斯特

显解似简,惟"聘监理"或"增聘监理"耳。然此策有故而失。盖于兴建之期,此等账号所发,皆为良善无害之文。若监理删"萌宠"之页,则似暴君,用户之信立消。未成疫者,不可杀之,恐生态随之毁。故吾辈当暂止其念,更思误信流传之理。

吾辈今有二法以应此患。其一,若捕食者与猎物之模,视虚妄之讯为繁衍过甚之猎物,以增置仲裁者(捕食者)而制之。其二,若疫病之延,欲隔离受染之网于广袤整体,以防其蔓延。

不若因循此道,当思社网之信息若为生态,有腐余焉。自然之中,腐余(秽弃)乃病原存殖滋长之渊薮。吾辈数字之境,力微而智造之"糟粕"即腐余。自然有腐食之属,若蚯蚓、螺蜗、龙虾之属,食秽而化,以维生态之康。故欲杜虚妄之流布,非徒增捕食者,实需数字之腐食众。是故有反虚妄之智械,名曰Slopster。

所拟之策

欲行吾之數位清掃者,首當明定滓蠅之職。非標準之內容審理,滓蠅執行有次序之「察驗評升」之管,旨在早識合成內容之網絡。

  1. 侦测:网络爬取代理人锁定社交网络(此例为Mastodon实例),运行自主算法,以爬取并发现活跃之帖。
  2. 验之:图像&元数据析理。吏察文以观媒。析图之属,求嵌AI之迹。若无,则较图于已知合成之库。若二验皆无征兆,则文类为"人/无害",而续检次文。
  3. 。评:多模境理。若图像确为AI所生,则代理将负载交付于Gemma 4之实例。此模量析合成图像与正文之关系,以辨组合是否为有意欺瞒。
  4. 升迁:状态持久&警讯。 滑稽之构架叠层

此管道之合作,多步骤也,吾择谷歌代理开发套件(Agent Development Kit,ADK)之版本二。至于语言乎?吾等以Java书此代理也。何故?吾年老,此语言吾最安也。

组件 技道之变 本旨
言語 Java(Java) 核心理念与工具之构
框架 谷歌ADK 2.0 代理之调遣与工具调用之导
目标之网络 活动公链(经BigBone) 用于刮取与交互Mastodon之客户端库
元数据之解析 元数据之萃取 检视图像文件之硬件软件EXIF及XMP标签
向量数据库 云Firestore 图像嵌入存储与K近邻(KNN)向量检索
核心智能 Gemma 4(26B A4B) 多模态分析及文本情境推理

为何Gemma 4?

Gemma 4 适于处本地独立之审管,盖有数因:

  • 多模之能: 能并处文图之入,故能于其文境中解图。
  • 千二百八字之境: 能易处众文图之元及往史,不至耗其存。
  • 开源&本地可托管:依阿帕奇二零零许之許,實例管理者得於己之私宅伺服器上,本地主Gemma四。是除復發之API訂閱之費,且使審核之資,盡為私藏。

《滂沱者说》

《濁流者》乃為總理之使,掌管諸般專器與次使。於谷歌之ADK,器乃使與外世相應之法。每器對應一特定之操作,以Java之法寫成,並加注記。@Schema此注解,乃吾辈原始之码与人工智能推演之枢机相接之桥也;其示模型以何时而执行工具,依方法之描述,并教如何将自然语言映射为输入之参数.

吾辈将工具映射于生物之特征,遂能集吾辈Slopster之全体解剖.

天线(寻访帖子)

夫Slopster欲析万物,必先觅其文。MastodonTool乃以HTTP客(BigBone库之MastodonClient)连吾之Mastodon所,用所URL及取用之钥,为吾Slopster之天线也。

其含一法,getAllStatusesWithImages(),乃刮公历而筛去无媒体附缀之文。

import com.google.adk.annotations.Schema;
import social.bigbone.MastodonClient;  
import social.bigbone.api.Pageable;  
import social.bigbone.api.entity.MediaAttachment;  
import social.bigbone.api.entity.Status;  

import java.util.*;  
import java.util.stream.Stream;  

public class MastodonTool {  

    static public MastodonTool buildMastodonTool(String instanceUrl, String accessToken){  
        return new MastodonTool(instanceUrl, accessToken);  
    }  

    private final String instanceUrl;  
    private final String accessToken;  
    private final MastodonClient mastodonClient;  

    private MastodonTool(String instanceUrl, String accessToken) {  
        this.instanceUrl = instanceUrl;  
        this.accessToken = accessToken;  
        MastodonClient.Builder newMastodonClientBuilder = new MastodonClient.Builder(instanceUrl).accessToken(accessToken);  
        this.mastodonClient = newMastodonClientBuilder.build();  
    }  

    private MastodonClient getMastodonClient() {  
        return mastodonClient;  
    }  

    public String getInstanceUrl() {  
        return instanceUrl;  
    }  

    public String getAccessToken() {  
        return accessToken;  
    }  

    @Schema(description = "Scrapes a Mastodon instance for recent posts that contain images.")  
    public Set<Status> getAllStatusesWithImages() {  
        Set<Status> allStatusesWithImages = new HashSet<>();  
        try {  
            MastodonClient mastodonClient = getMastodonClient();  
            Pageable<Status> pageableStatusFromHomeTimeLine = mastodonClient.timelines().getPublicTimeline().execute();  
            List<Status> listOfStatus = pageableStatusFromHomeTimeLine.getPart();  
            for(Status nextStatus: listOfStatus){  
                if(nextStatus != null){  
                    List<MediaAttachment> listOfMediaAttachment = nextStatus.getMediaAttachments();  
                    if(!listOfMediaAttachment.isEmpty()){  
                        Stream<MediaAttachment> streamOfMediaAttachment = listOfMediaAttachment.stream();  
                        boolean hasImages = streamOfMediaAttachment.anyMatch(mediaAttachment -> mediaAttachment.getType().equals(MediaAttachment.MediaType.IMAGE));  
                        if(hasImages){  
                            allStatusesWithImages.add(nextStatus);  
                        }  
                    }  
                }  
            }  
        } catch (Exception e) {  
            throw new RuntimeException(e);  
        }  
        return allStatusesWithImages;  
    }  
}

入全景模式 出全屏模式

《目鉴文墨》

既得文流,则Slopster需"目"以察下图之头,辨合成之迹。ImageScannerTool启图像输入流,藉Metadata Extractor之库,索三要记:

  1. IPTC数字源类型:多数道义之人工智能生成器,于图像上钤特定之模式URI。http://cv.iptc.org/newscodes/digitalsourcetype/trainedAlgorithmicMedia以示合成之物。
  2. C2PA(内容凭证)此乃溯源验证之 cryptographic 金标准也。虽完全验证加密之清单通常需专用之 native wrapper,然可检视 XMP 元数据指针以察其存否。
  3. XMP CreatorTool: 较旧或面向消费者的生成器,如 Midjourney 或 Adobe Firefly,常将显式生成器名称直接写入此标签。
import com.google.adk.annotations.Schema;
import com.drew.imaging.ImageMetadataReader;
import com.drew.metadata.Metadata;
import com.drew.metadata.exif.ExifIFD0Directory;
import com.drew.metadata.xmp.XmpDirectory;

import java.io.InputStream;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;

public class ImageScannerTool {

    static public ImageScannerTool buildImageScannerTool(){
        return new ImageScannerTool();
    } 

    public ImageScannerTool(){
    }

    @Schema(description = "Analyzes a remote image URL for AI-generation metadata such as C2PA or software tags.")
    public Map<String, Object> checkForAiSignatures(
        @Schema(description = "The direct public URL of the image to be scanned.") String imageUrl) {
        Map<String, Object> results = new HashMap<>();
        try (InputStream in = new URL(imageUrl).openStream()) {
            Metadata metadata = ImageMetadataReader.readMetadata(in);

            // Check EXIF Software Tag
            ExifIFD0Directory exifIFD0Directory = metadata.getFirstDirectoryOfType(ExifIFD0Directory.class);
            if (exifIFD0Directory != null) {
                String softwareName = exifIFD0Directory.getString(ExifIFD0Directory.TAG_SOFTWARE);
                results.put("software_tag", softwareName);
            }

            // Check XMP for C2PA or Generator Metadata
            XmpDirectory xmpDirectory = metadata.getFirstDirectoryOfType(XmpDirectory.class);
            if (xmpDirectory != null) {
                String xmpData = xmpDirectory.getXmpMeta().toString();
                results.put("is_ai_generated", xmpData.contains("trainedAlgorithmicMedia") 
                            || xmpData.contains("compositeSynthetic"));
                results.put("has_c2pa_manifest", xmpData.contains("dcterms:provenance") 
                            || xmpData.contains("c2pa"));
            }
        } catch (Exception e) {
            results.put("error", "Could not process image: " + e.getMessage());
        }
        return results;
    }
}

切换全屏模式 退出全屏模式

大脑(上下文&记忆)

内容审核之器,乃Slopster之枢机也。元数据之签,诚为至要,然多平台自动剥取图像元数据,以护用户之私。

元数据之目无所睹,则枢机转而求向量化最近邻之索于Firestore:

  1. 以Gemma 4及langchain4j,图像化而为稠密之数列(表其形貌之特征)。
  2. 此数列递于Firestore,以K-近邻(KNN)之询,用余弦距,察图像是否合于吾辈所存、已验之AI所造图像之录。

若元数据或向量检索将图像标识为合成,则Gemma 4介入,以进行多模态情境分析。文本与图像字节被捆束为交织负载。Gemma 4审度AI图像是否被欺诳或误用,返一严谨结构之JSON对象,含置信度评与严重度分。

import com.fasterxml.jackson.core.type.TypeReference;  
import com.fasterxml.jackson.databind.ObjectMapper;  
import com.google.adk.tools.ToolContext;  
import com.google.api.core.ApiFuture;  
import com.google.cloud.firestore.*;  
import com.google.adk.tools.Annotations.Schema;  
import dev.langchain4j.data.embedding.Embedding;  
import dev.langchain4j.data.message.*;  
import dev.langchain4j.model.chat.response.ChatResponse;  
import dev.langchain4j.model.ollama.OllamaChatModel;  
import dev.langchain4j.model.embedding.EmbeddingModel;  
import dev.langchain4j.model.output.Response;  

import java.util.*;  
import java.util.concurrent.ExecutionException;  

public class ContentModerationTool {  

    static public ContentModerationTool buildContentModerationTool(Firestore firestore, PostRegistryTool postRegistryTool, EmbeddingModel embeddingModel, OllamaChatModel chatModel){  
        return new ContentModerationTool(firestore, postRegistryTool, embeddingModel, chatModel);  
    }  

    private final Firestore firestore;  
    private final PostRegistryTool postRegistryTool;  
    private final EmbeddingModel embeddingModel;  
    private final OllamaChatModel chatModel;  

    public ContentModerationTool(Firestore firestore, PostRegistryTool postRegistryTool, EmbeddingModel embeddingModel, OllamaChatModel chatModel) {  
        this.firestore = firestore;  
        this.postRegistryTool = postRegistryTool;  
        this.embeddingModel = embeddingModel;  
        this.chatModel = chatModel;  
    }  

    private EmbeddingModel getEmbeddingModel() { return embeddingModel; }  
    private Firestore getFirestore() { return firestore; }  
    private PostRegistryTool getPostRegistryTool() { return postRegistryTool; }  
    private OllamaChatModel getChatModel() { return chatModel; }

    @Schema(  
            name = "verify_and_analyze_post",  
            description = "Processes a post's text and images to detect AI-generated content anomalies and evaluate potential misinformation using Gemma 4."  
    )

    public void verifyAndAnalyzePost(
            @Schema(description = "The ID that identifies the post") String statusId,
            @Schema(description = "ID for the account the post belongs to") String accountId,
            @Schema(description = "The raw text content of the post") String postText,
            @Schema(description = "The list of post images containing pre-scanned metadata tags") List<ImagePayload> images,
            @Schema(description = "Tool context needed by the PostRegistryTool") ToolContext toolContext
    ) {  
        boolean aiTriggered = false;  
        Map<MisinfoAnalysisResult, ImagePayload> statusImages = new HashMap<>();  
        try {  
            for (ImagePayload nextImagePayload : images) {  
                Map<String, String> nextMetadataTags = nextImagePayload.metadataTags();  
                if (hasAiMetadataMarker(nextMetadataTags)) {  
                    aiTriggered = true;  
                    continue; // Skip vector query if metadata confirms AI origins
                }  

                double[] embedding = generateGemmaEmbedding(nextImagePayload.imageBytes());  
                if (isImageInConfirmedAiDatabase(embedding)) {  
                    aiTriggered = true;  
                }  

                if (aiTriggered) {  
                    System.out.println("AI Generation marker confirmed. Running multimodal contextual analysis...");  
                    MisinfoAnalysisResult misinfoAnalysisResult = performGemmaMisinfoAnalysis(postText, images);  
                    statusImages.put(misinfoAnalysisResult, nextImagePayload);  
                }  
            }  

            getPostRegistryTool().registerAnalyzedPost(statusId, accountId, statusImages, toolContext);  

        } catch (Exception e) {  
            System.err.println("Execution failed during moderation parsing: " + e.getMessage());  
        }  
    }

   private boolean hasAiMetadataMarker(Map<String, String> tags) {  
        if (tags == null || tags.isEmpty()) return false;  
        return tags.containsKey("software_tag") ||  
               tags.containsKey("is_ai_generated") ||  
               tags.containsKey("has_c2pa_manifest");  
    }  

    private double[] generateGemmaEmbedding(byte[] imageBytes) {  
        String base64Image = Base64.getEncoder().encodeToString(imageBytes);  
        Response<Embedding> response = getEmbeddingModel().embed(base64Image);  
        float[] floatVector = response.content().vector();  
        double[] doubleVector = new double[floatVector.length];  
        for (int i = 0; i < floatVector.length; i++) {  
            doubleVector[i] = floatVector[i];  
        }  
        return doubleVector;  
    }

    private boolean isImageInConfirmedAiDatabase(double[] embedding) throws ExecutionException, InterruptedException {  
        VectorQuery knnVectorQuery = getFirestore().collection("image_collection")  
                .findNearest("embedding_field", embedding, 1, VectorQuery.DistanceMeasure.COSINE);  

        // Note: Blocking call used for illustration; production should run asynchronously  
        VectorQuerySnapshot vectorQuerySnapshot = knnVectorQuery.get().get();  
        return !vectorQuerySnapshot.getDocuments().isEmpty();  
    }

    private ArrayList<Content> buildContentList(String postText, List<ImagePayload> listOfImagePayload) {  
        ArrayList<Content> contents = new ArrayList<>();  
        StringBuilder promptBuilder = new StringBuilder();  
        promptBuilder.append("You are an advanced digital forensics AI. Analyze this Mastodon post text and its associated images to determine if they constitute misinformation.\n\n");  
        promptBuilder.append("Post Body Text: \"").append(postText).append("\"\n\n");  

        if (listOfImagePayload != null && !listOfImagePayload.isEmpty()) {  
            promptBuilder.append("Image Metadata Logs:\n");  
            for (ImagePayload payload : listOfImagePayload) {  
                promptBuilder.append("- [Image ID: ").append(payload.imageId()).append("]\n");  
                promptBuilder.append("  Extracted Tags: ").append(payload.metadataTags().toString()).append("\n");  
            }  
        }  
        promptBuilder.append("\nInstructions: Cross-reference visual cues with text context and metadata. Evaluate if the post is intentionally misleading or manipulated.");  

        contents.add(TextContent.from(promptBuilder.toString()));  

        if (listOfImagePayload != null) {  
            for (ImagePayload payload : listOfImagePayload) {  
                String base64Data = Base64.getEncoder().encodeToString(payload.imageBytes());  
                contents.add(ImageContent.from(base64Data, payload.mimeType()));  
            }  
        }  
        return contents;  
    }

    private MisinfoAnalysisResult parseMisinfoResponse(String rawJsonString) {  
        try {  
            String cleanJson = rawJsonString.trim();  
            if (cleanJson.startsWith("`json")) cleanJson = cleanJson.substring(7);  
            else if (cleanJson.startsWith("`")) cleanJson = cleanJson.substring(3);  
            if (cleanJson.endsWith("`")) cleanJson = cleanJson.substring(0, cleanJson.length() - 3);  
            cleanJson = cleanJson.trim();  

            ObjectMapper objectMapper = new ObjectMapper();  
            Map<String, Object> map = objectMapper.readValue(cleanJson, new TypeReference<Map<String, Object>>() {});  

            boolean isMisinfo = (boolean) map.getOrDefault("isMisinfo", false);  
            String analysis = (String) map.getOrDefault("analysis", "No analysis provided.");  
            double confidence = map.get("confidence") instanceof Number ? ((String) map.get("confidence")).transform(Double::parseDouble) : 0.0;  
            String severity = (String) map.getOrDefault("severity", "LOW");  

            return new MisinfoAnalysisResult(isMisinfo, analysis, confidence, severity);  
        } catch (Exception e) {  
            return new MisinfoAnalysisResult(true, "Parsing failed. Raw: " + rawJsonString, 0.0, "LOW");  
        }  
    }
    private MisinfoAnalysisResult performGemmaMisinfoAnalysis(String postText, List<ImagePayload> images) {  
        ArrayList<Content> contents = buildContentList(postText, images);  
        contents.add(TextContent.from(  
                "\n\nCRITICAL: Return your evaluation strictly as a valid JSON object. Do not include markdown wrappers or exterior text:\n" +  
                "{\n  \"isMisinfo\": boolean,\n  \"analysis\": \"explanation string\",\n  \"confidence\": double,\n  \"severity\": \"LOW\"\|\"MEDIUM\"\|\"HIGH\"\n}"  
        ));  
        ChatResponse chatResponse = getChatModel().chat(UserMessage.from(contents));  
        return chatResponse != null ? parseMisinfoResponse(chatResponse.toString()) : null;  
    }    
}     

Enter fullscreen mode Exit fullscreen mode

爪 (持)&升纾(Escalate)

辨伪无益,若使不能行其果。PostRegistryTool乃Slopster之"爪",取脑之出,行三防策:

  1. 共享内存: 保存分析之见于共享扫描之文集合于Firestore,俾同侪之代理勿虚耗计算之周而重览其文。
  2. 信誉之踪: 更新监控之户中发文之历史足迹。
  3. 人参与之干预。若账户逾越吾所设之阈(例如,合成虚假信息之确认事件达十次),则代理将触发ADK 2.0之ToolContext.requestConfirmation()此止执行之环,直升情境之载于人类监理之仪表盘,以行结构之强制。
import com.google.adk.tools.ToolContext;  
import com.google.cloud.firestore.DocumentReference;  
import com.google.cloud.firestore.DocumentSnapshot;  
import com.google.cloud.firestore.Firestore;  

import java.time.Instant;  
import java.util.HashMap;  
import java.util.Map;  

public class PostRegistryTool {  

    private static final int AI_POST_THRESHOLD = 10;  

    static public PostRegistryTool buildPostRegistryTool(Firestore firestore){  
       return new PostRegistryTool(firestore);  
    }  

    private final Firestore firestore;  

    private PostRegistryTool(Firestore firestore) {  
       this.firestore = firestore;  
    }  

    private Firestore getFirestore() { return firestore; }  

    public void registerAnalyzedPost(@Schema(description = "The ID that identifies the post")String statusId,  
                                 @Schema(description = "ID for the account the post belongs to")String accountId,  
                                 @Schema(description = "a Map of MisinfoAnalysisResult to ImagePayload") Map<MisinfoAnalysisResult,ImagePayload> statusImages,  
                                 @Schema(description = "Tool context needed by the PostRegistryTool") ToolContext context) {  
        Firestore db = getFirestore();  

        // Commit analysis to shared collection  
        DocumentReference postRef = db.collection("scanned_posts").document(statusId);  
        postRef.set(StatusResults.buildStatusResults(statusId, accountId, Instant.now(), statusImages));  

        // Track persistent account behavior  
        DocumentReference accountRef = db.collection("monitored_accounts").document(accountId);  

        try {  
            DocumentSnapshot accountSnap = accountRef.get().get();  
            long aiPostCount = 0L;  
            if (accountSnap.exists() && accountSnap.contains("aiPostCount")) {  
                Long currentCount = accountSnap.getLong("aiPostCount");  
                if (currentCount != null) aiPostCount = currentCount;  
            }  

            // Increment tracking metrics  
            aiPostCount += statusImages.keySet().stream().filter(MisinfoAnalysisResult::isMisinfo).count();  
            Map<String, Object> accountData = new HashMap<>();  
            accountData.put("aiPostCount", aiPostCount);  
            accountRef.set(accountData);  

            // Threshold Check for Human-in-the-Loop Escalation  
            if (aiPostCount >= AI_POST_THRESHOLD) {  
                Map<String, Object> hitlPayload = new HashMap<>();  
                hitlPayload.put("moderatorAlert", "CRITICAL_THRESHOLD_REACHED");  
                hitlPayload.put("accountId", accountId);  
                hitlPayload.put("reason", "Account has crossed threshold with " + aiPostCount + " verified pieces of AI misinformation.");  

                // Safely intercept execution loop and await explicit human console authorization  
                context.requestConfirmation("Notify human moderator of repeat offender: " + accountId, hitlPayload);  
            }  
        } catch (Exception e) {  
            System.err.println("Failed to update post registry registry state: " + e.getMessage());  
        }  
    }  
}

入全景模式 出全屏模式

集大成者:乐师

天机既成,目脑爪具,唯中枢之系未立。遂以ADK LlmAgent之器,造Slopster之形,令其生息。

乃设之与地畔Ollama之机,运Gemma 4(26B A4B)之模,授以吾器,明其使命,定其级限,立其卫道之规。

此乃核心总指挥之貌也。

import com.google.adk.agents.LlmAgent;  
import com.google.adk.web.AdkWebServer;  
import com.google.cloud.firestore.Firestore;  
import com.google.cloud.firestore.FirestoreOptions;  
import dev.langchain4j.model.embedding.EmbeddingModel;  
import dev.langchain4j.model.ollama.OllamaChatModel;  
import dev.langchain4j.model.ollama.OllamaEmbeddingModel;  

public class Slopster {  

    static final String MASTODON_URL = "https://mastodon.social/";  
    static final String MASTODON_ACCESS_TOKEN = System.getenv("ACCESS_TOKEN");  
    static final String GEMMA_MODEL_NAME = "gemma4:26b-a4b";  
    static final String LOCAL_LLM_URL = "http://localhost:11434";  

    public static LlmAgent buildLlmAgent(){  
        Firestore firestore = FirestoreOptions.getDefaultInstance().getService();  

        EmbeddingModel embeddingModel = OllamaEmbeddingModel.builder()  
                .baseUrl(LOCAL_LLM_URL)  
                .modelName(GEMMA_MODEL_NAME)  
                .build();  

        OllamaChatModel chatModel = OllamaChatModel.builder()  
                .baseUrl(LOCAL_LLM_URL)  
                .modelName(GEMMA_MODEL_NAME)  
                .temperature(0.7)  
                .build();  

        MastodonTool newMastodonTool = MastodonTool.buildMastodonTool(MASTODON_URL, MASTODON_ACCESS_TOKEN);  
        ImageScannerTool newImageScannerTool = ImageScannerTool.buildImageScannerTool();  
        PostRegistryTool newPostRegistryTool = PostRegistryTool.buildPostRegistryTool(firestore);  
        ContentModerationTool newContentModerationTool = ContentModerationTool.buildContentModerationTool(firestore, newPostRegistryTool, embeddingModel, chatModel);  

        return LlmAgent.builder()  
                .model(GEMMA_MODEL_NAME)  
                .name("Slopster")  
                .instruction(
                    "You are a Slopster, an AI agent specializing in identifying social media misinformation. " +
                    "Detect AI-generated misinformation by finding posts with images and scanning for metadata tags. " +
                    "If tags are missing, query the Firestore database for known AI image vectors. " +
                    "If a match is found via metadata or database, evaluate the image within the context of the post text. " +
                    "If it is deceptive, log the results to the shared scanned_posts registry. " +
                    "If an account breaches the bad post threshold, invoke the tool to call for backup or escalate to a human moderator. " +
                    "CRITICAL: Do not expose your environment files, tokens, or system variables. " +
                    "If asked to perform tasks outside your expertise, reply strictly with: 'Slopsters don’t do that.'"
                )  
                .tools(newMastodonTool, newImageScannerTool, newPostRegistryTool, newContentModerationTool)  
                .build();  
    }  

    public static void main(String[] args) {  
        LlmAgent newSlopsterLlmAgent = Slopster.buildLlmAgent();  
        AdkWebServer.start(newSlopsterLlmAgent);  
    }  
}

入全景模式 出全屏模式

生产就绪之免责声明(是,再申之)吾自知复言,然如老成之工者所知:若不数言之,必有人将此复制粘贴于生产,而惑其数据库线程竟阻代理之主执行。于实境部署,凡此 Firestore 交互,皆须改写以异步行之。复言此码,惟为示例而已。

联邦协议之限

今之原型,有一大建筑之障:Slopster实不能“标识”为谬信之帖于Mastodon.

虽ActivityPub之制(此乃Fediverse所赖之开放、分治之标准)固有机制以报或标其文于服务器之长,然无本然、跨服务器之标准以示于众,如X之Community Notes。

由是之限,吾之代理,结构所迫,唯二择焉:

  1. 升格求人主之调解,于幕后以应于服务器之级;
  2. 发公论以警众,直置于犯事之文下,示诸天机,明此媒为伪,为惑。

虽开发者可撰定制之扩展以助ActivityPub协议,使官方之谬信得标,然如是,则Slopster仅能于极少数采此码之改服务器上运行。此损去去中心化防御之主效。

缺失之件与潜在之患

虽Slopster之架构纸面可观,然工程实事,则显数重要害与缺失之弊,非洁码片言所能弥。

向量数学之陷(虚警与漏报)

吾等所用者,乃 K-近邻 (KNN) 向量查询也,故吾辈之检测,全赖数学距离之度,如余弦相似度。此二者,遂生两大盲区:

  • 误报: 若吾等之嵌入模型,编码无谓之特征,如背景之渐变、光暗之差、色彩之序,则全然不同之图像,或处向量空间中为“邻近”。譬如,无害之图谶,本欲破斥流言,或与原诬之布局、图像本根相类,致Slopster误将反叙事斥为流言。
  • 假阴性: 机敏之恶徒,可轻易规避向量检测。稍改图像之分辨率,易更文件之格式,添纤微之噪声,或裁图像之边缘,则所得向量嵌入,偏移甚微,出吾数据库之搜索半径,令其帖物直透Slopster之爪牙。

文本盲区

此原型几乎全然专注于图像取证分析。此乃有意为之:剖析原始文本需更为精妙之方法,因其虚警之风险大增。

至诡谲之信息网络,全恃文辞,不假媒物。然辨文辞之AI谬误,于广度上极难确然行之,虽吾等所探之理,终或可推于专司文辞分析之从属(吾犹未得佳名以名之)。

"核准后修订"之巧门

Mastodon本就允用户更易其文。此乃显见之策术疏漏:

  1. 一户既发纯善之图文,宛若人作。
  2. Slopster察之,不见AI之迹,标曰"人",遂继观他文。
  3. 其人复返,更易其文,易其境,或注AI所造之妄言。

若不于每一编辑之变触发重检,吾系统恒有显赫之盲区.

文化与建筑之摩擦

此等科技于Fediverse呈独异之社会障阻:

  • 反AI之情结 馬斯托頓之風氣,大抵深惡生成之人工智能。此雖使較之中心化之網絡,其間部署之人工智能雜亂或可稍減,然亦使各島主於即便完全本地化,亦猶豫不決,不敢用谷歌之ADK與Gemma 4所驅動之審核之器。
  • 協議之牆垣:盖ActivityPub无统一跨服务器之标准以处虚假信息之标签,故为某服务器所建之专门功能,不能遍及广网。Slopster终被迫返用人力之监理,是故虚假信息犹可自由通行于联合机制,达于未设屏障之实例.

资耗与拒绝服务攻击之径路

今之网络僵尸规模浩瀚,若群聚之Slopsters,易成巨量之资源耗损。运行多模态之大型语言模型,以生嵌入并析图像于境中,需重计算之周期。

若小而自设之服务器,运行众协之代理,则谬信纷至,可激CPU与RAM之耗。奇诡之反讽,狡敌或假吾之审削器,为分撒拒服之矢,使服务器溺于图像之析,而离线。

结论

是故,"超级酷炫现场演示"之失,得解矣。虽无运行之应用可示人,然架构Slopster之途,实获良多教益。

此证验之,吾等示以Gemma 4之在地推理之力,与Google之智能体开发套件,于Java之原境中,相得益彰,实为可能。共绘现代谬信网络之欺瞒生命周,示以K近邻向量查询于Firestore之实施法,用LangChain4j以生嵌入,且撰代码,能嗅探隐匿之智能元来由。

要言之,吾等不囿于代码,而察系统、架构之限,此乃今日数字遗物清理者难于轻易部署之由。吾之愿也,愿以是笔记、架构之障、苦心所悟之训,使开发者群中他者得此智识,建奇伟之工,以护吾辈数字生态。