AI学习记录 - 规范化输出对接现有系统的实例

news2024/11/15 4:55:22

假设我们有一个学生管理系统,通过prompt提示,格式化输出然后对接现有系统,也是通过react实现,因为这只是一个知识分享,没弄太复杂(使用react实现)。

学生管理系统

在这里插入图片描述

1、设计好prompt


    getMemory() {
        return [
            {
                content: "我有一个系统处理人物信息 我有json格式数据是一个数组,数组每一项格式如:" +
                    "person: { \"name姓名\": \"Cathy\", \"age年龄\": 25, \"gender性别\": \"female\"," +
                    " \"hometown家乡\": \"Guangzhou\", \"occupation职业\": \"teacher\" }。" +
                    " 我有四个方法 addPerson(person)新增人物;removePerson(person)传入person对象 " +
                    "里面依据name删除人物;findPerson(person)根据persion对象的name查询人物;" +
                    "updatePerson(person)传入person对象里面根据name查询人物;updateAllPerson(person)传入属性," +
                    "可以修改全部人的属性,例如传入{\"age\": 25},所有的人年龄都修改成25。" +
                    " 下面我给你指令,请你调用适当的方法,传入适当的参数帮助我操作系统。 例如:我说:帮我删除名字为david的人," +
                    "你就返回指令:@{\"methods\":\"removePerson\",\"data\":{\"name\":\"david\"}}@;每条指令只能操作一个人物," +
                    "你可以返回多条指令;是否明白",
                role: "user",
            },
            {
                content: "明白了。以下是根据您的指令给出的操作:帮我新增一个人,名字叫做Tom,年龄为30,性别为male,家乡为Shanghai,职业为engineer。" +
                    "返回指令:帮我新增一个人,名字叫做Tom,年龄为30,性别为male,家乡为Shanghai,职业为engineer。" +
                    "返回指令:@{\"methods\":\"addPerson\",\"data\":{\"name\":\"Tom\",\"age\":30,\"gender\":\"male\",\"hometown\":\"Shanghai\",\"occupation\":\"engineer\"}}@" +
                    "帮我删除名字为Cathy的人。" +
                    "返回指令:@{\"methods\":\"removePerson\",\"data\":{\"name\":\"Cathy\"}}@" +
                    "帮我查找名字为John的人。" +
                    "返回指令:@{\"methods\":\"findPerson\",\"data\":{\"name\":\"John\"}}@" +
                    "帮我更新名字为Lucy的人的信息,把家乡改为Beijing,职业改为doctor。" +
                    "返回指令:@{\"methods\":\"updatePerson\",\"data\":{\"name\":\"Lucy\",\"hometown\":\"Beijing\",\"occupation\":\"doctor\"}}@",
                role: "assistant"
            }
        ]
    }

2、设计好对应的系统api代码


    addPerson(person) {
        this.list.push(person);
    }

    removePerson(person) {
        const index = this.list.findIndex((p) => p.name.toLowerCase() === person.name.toLowerCase());
        if (index !== -1) {
            this.list.splice(index, 1);
        }
    }

    findPerson(person) {
        if (person.name === "") {
            return this.list;
        }
        return this.list.filter((p) => p.name.toLowerCase() === person.name.toLowerCase());
    }

    updatePerson(person) {
        const index = this.list.findIndex((p) => p.name.toLowerCase() === person.name.toLowerCase());
        if (index !== -1) {
            this.list[index] = {
                ...this.list[index],
                ...person
            };
        }
    }

    updateAllPerson(attr, callback) {
        let arr = this.list.map((item) => {
            return {
                ...item,
                ...attr
            }
        });
        this.list = arr;
        console.log("arr", arr);
        if (callback) callback(arr);
    }

3、解析gpt返回字符的方法

    action = (str, callback) => {
        const match = str.match(/@(.*?)@/g);
        console.log("match", match);
        if (match.length) {
            match.map((gptOrder) => {
                const match = gptOrder.match(/@(.*?)@/);
                const result = match ? match[1] : null;
                let json = JSON.parse(result);
                this[json.methods](json.data);
            });
            callback({
                result: true,
                response: "操作成功"
            });
        } else {

            callback({
                result: false,
                response: str
            });
        }
    }

全部代码,
index.js


import React, { useContext, useState, useCallback, useRef, useEffect } from 'react';
import People from "./People";


import { Space, Table, Drawer, Form, Input, Button, message } from 'antd';
const { Search } = Input;
const { TextArea } = Input;


const App = () => {
  const people = useRef(new People());
  const [messageApi, contextHolder] = message.useMessage();
  const key = 'updatable';
  const [actionType, setActionType] = useState(false);
  const [textAreaValue, setTextAreaValue] = useState("");
  const [open, setOpen] = useState(false);
  const [list, setList] = useState([]);

  const [initialValues, setInitialValues] = useState({});
  useEffect(() => {
    setList(people.current.list);
  }, []);
  const success = () => {
    messageApi.open({
      key,
      type: 'loading',
      content: 'ChatGPT Loading ...',
      duration: 30
    });
  };
  const onFinish = (values) => {
    setInitialValues({});
    if (actionType === "update") {
      people.current.updatePerson(values);
      setOpen(false);
      setList(JSON.parse(JSON.stringify(people.current.list)));
    } else {
      people.current.addPerson(values);
      setOpen(false);
      setList(JSON.parse(JSON.stringify(people.current.list)));
    }
  }
  const getTable = () => {
    const columns = [
      {
        title: '姓名',
        dataIndex: 'name',
        key: 'name',
      },
      {
        title: '年龄',
        dataIndex: 'age',
        key: 'age',
      },
      {
        title: '性别',
        dataIndex: 'gender',
        key: 'gender',
      },
      {
        title: '老家',
        dataIndex: 'hometown',
        key: 'hometown',
      },
      {
        title: '职业',
        dataIndex: 'occupation',
        key: 'occupation',
      },
      {
        title: 'Action',
        key: 'action',
        render: (_, record) => (
          <Space size="middle">
            <a onClick={() => {
              setOpen(true);
              setInitialValues(record);
              setActionType("update");
            }}>edit</a>
            <a onClick={() => {
              people.current.removePerson(record);
              setList(JSON.parse(JSON.stringify(people.current.list)));
            }}>delete</a>
          </Space>
        ),
      },
    ];
    const onSearch = (value) => {
      setList(JSON.parse(JSON.stringify(people.current.findPerson(value))));
    }
    // useEffect(() => {
    //   success();
    // }, [open])
    return (
      <div style={{ padding: 20 }}>
        {contextHolder}
        <Button style={{ marginRight: 10 }} type="primary" onClick={() => {
          setInitialValues(() => { });
          setOpen(true);
          setActionType("add");
        }}>
          News
        </Button>
        <Search style={{ marginLeft: 20 }} placeholder="input search text" onSearch={onSearch} style={{ width: 200 }} />
        <Button style={{ marginRight: 10 }} type="primary" onClick={() => {
          success();
          people.current.toChatGPT(textAreaValue, (result) => {
            if (result.result) {
              messageApi.open({
                key,
                type: 'success',
                content: result.response,
                duration: 2,
              });
              setList(JSON.parse(JSON.stringify(people.current.list)));
            } else {
              messageApi.open({
                key,
                type: 'fail',
                content: result.response,
                duration: 2,
              });
            }
          });
        }}>
          执行
        </Button>
        <div style={{ marginTop: 10 }}>
          <TextArea
            placeholder='你可以要求chatgpt帮助你完成某些内容'
            onChange={(e) => {
              setTextAreaValue(e.target.value)
            }}
          />

        </div>

        <Table dataSource={list} columns={columns} />
        <Drawer
          onClose={() => { setOpen(false); }}
          title="Basic Drawer" placement="right" open={open}>
          {
            open ? (
              <Form
                name="basic"
                labelCol={{ span: 8 }}
                wrapperCol={{ span: 16 }}
                style={{ maxWidth: 600 }}
                initialValues={initialValues}
                onFinish={onFinish}
                autoComplete="off"
              >
                <Form.Item
                  label="name"
                  name="name"
                >
                  <Input disabled={actionType === "add" ? false : true} />
                </Form.Item>
                <Form.Item
                  label="age"
                  name="age"
                >
                  <Input />
                </Form.Item>
                <Form.Item
                  label="gender"
                  name="gender"
                >
                  <Input />
                </Form.Item>
                <Form.Item
                  label="hometown"
                  name="hometown"
                >
                  <Input />
                </Form.Item>
                <Form.Item
                  label="occupation"
                  name="occupation"
                >
                  <Input />
                </Form.Item>
                <Form.Item wrapperCol={{ offset: 8, span: 16 }}>
                  <Button type="primary" htmlType="submit">
                    Submit
                  </Button>
                </Form.Item>
              </Form>
            ) : null
          }
        </Drawer>
      </div>

    )
  }
  const getChart = () => {
    return (
      <div id="main">

      </div>
    )
  }
  return (
    <div>
      {getTable()}
      {getChart()}
    </div>
  )
}
export default App;

人物类
people.js

import axios from 'axios';
class People {
    constructor(name, age, gender, hometown, occupation) {
        this.name = name;
        this.age = age;
        this.gender = gender;
        this.hometown = hometown;
        this.occupation = occupation;
        this.list = [];
        this.addPerson({ name: "Cathy", age: 25, gender: "female", hometown: "Guangzhou", occupation: "teacher" });
        this.addPerson({ name: "David", age: 28, gender: "male", hometown: "Chengdu", occupation: "designer" });
        this.addPerson({ name: "Emily", age: 31, gender: "female", hometown: "Hangzhou", occupation: "writer" });
        this.addPerson({ name: "Frank", age: 37, gender: "male", hometown: "Suzhou", occupation: "entrepreneur" });
        this.addPerson({ name: "Alice", age: 23, gender: "female", hometown: "Beijing", occupation: "student" });
        this.addPerson({ name: "Bob", age: 30, gender: "male", hometown: "Shanghai", occupation: "engineer" });
        this.addPerson({ name: "George", age: 22, gender: "male", hometown: "Wuhan", occupation: "student" });
        this.addPerson({ name: "Helen", age: 29, gender: "female", hometown: "Tianjin", occupation: "doctor" });
        this.addPerson({ name: "Isaac", age: 27, gender: "male", hometown: "Xian", occupation: "researcher" });
        this.addPerson({ name: "Julia", age: 33, gender: "female", hometown: "Nanjing", occupation: "manager" });
        this.addPerson({ name: "Kevin", age: 26, gender: "male", hometown: "Chongqing", occupation: "teacher" });
        this.addPerson({ name: "Lily", age: 24, gender: "female", hometown: "Shenzhen", occupation: "engineer" });
        this.addPerson({ name: "Mike", age: 30, gender: "male", hometown: "Qingdao", occupation: "entrepreneur" });
        this.addPerson({ name: "Nancy", age: 28, gender: "female", hometown: "Zhengzhou", occupation: "designer" });
        this.addPerson({ name: "Oscar", age: 35, gender: "male", hometown: "Ningbo", occupation: "writer" });
        this.addPerson({ name: "Penny", age: 27, gender: "female", hometown: "Changsha", occupation: "student" });
        this.addPerson({ name: "Quincy", age: 29, gender: "male", hometown: "Fuzhou", occupation: "teacher" });
        this.addPerson({ name: "Rose", age: 32, gender: "female", hometown: "Shijiazhuang", occupation: "doctor" });
        this.addPerson({ name: "Simon", age: 36, gender: "male", hometown: "Wuxi", occupation: "researcher" });
        this.addPerson({ name: "Tina", age: 31, gender: "female", hometown: "Changchun", occupation: "manager" });
        this.addPerson({ name: "Vincent", age: 34, gender: "male", hometown: "Harbin", occupation: "designer" });
        this.addPerson({ name: "Wendy", age: 26, gender: "female", hometown: "Foshan", occupation: "manager" });
        this.addPerson({ name: "Xavier", age: 28, gender: "male", hometown: "Yangzhou", occupation: "entrepreneur" });
        this.addPerson({ name: "Yvonne", age: 33, gender: "female", hometown: "Jinan", occupation: "teacher" });
        this.addPerson({ name: "Zack", age: 30, gender: "male", hometown: "Zhuhai", occupation: "writer" });
        this.addPerson({ name: "Alice", age: 29, gender: "female", hometown: "Haikou", occupation: "doctor" });
    }


    addPerson(person) {
        this.list.push(person);
    }

    removePerson(person) {
        const index = this.list.findIndex((p) => p.name.toLowerCase() === person.name.toLowerCase());
        if (index !== -1) {
            this.list.splice(index, 1);
        }
    }

    findPerson(person) {
        if (person.name === "") {
            return this.list;
        }
        return this.list.filter((p) => p.name.toLowerCase() === person.name.toLowerCase());
    }

    updatePerson(person) {
        const index = this.list.findIndex((p) => p.name.toLowerCase() === person.name.toLowerCase());
        if (index !== -1) {
            this.list[index] = {
                ...this.list[index],
                ...person
            };
        }
    }

    updateAllPerson(attr, callback) {
        let arr = this.list.map((item) => {
            return {
                ...item,
                ...attr
            }
        });
        this.list = arr;
        console.log("arr", arr);
        if (callback) callback(arr);
    }

    getMemory() {
        return [
            {
                content: "我有一个系统处理人物信息 我有json格式数据是一个数组,数组每一项格式如:" +
                    "person: { \"name姓名\": \"Cathy\", \"age年龄\": 25, \"gender性别\": \"female\"," +
                    " \"hometown家乡\": \"Guangzhou\", \"occupation职业\": \"teacher\" }。" +
                    " 我有四个方法 addPerson(person)新增人物;removePerson(person)传入person对象 " +
                    "里面依据name删除人物;findPerson(person)根据persion对象的name查询人物;" +
                    "updatePerson(person)传入person对象里面根据name查询人物;updateAllPerson(person)传入属性," +
                    "可以修改全部人的属性,例如传入{\"age\": 25},所有的人年龄都修改成25。" +
                    " 下面我给你指令,请你调用适当的方法,传入适当的参数帮助我操作系统。 例如:我说:帮我删除名字为david的人," +
                    "你就返回指令:@{\"methods\":\"removePerson\",\"data\":{\"name\":\"david\"}}@;每条指令只能操作一个人物," +
                    "你可以返回多条指令;是否明白",
                role: "user",
            },
            {
                content: "明白了。以下是根据您的指令给出的操作:帮我新增一个人,名字叫做Tom,年龄为30,性别为male,家乡为Shanghai,职业为engineer。" +
                    "返回指令:帮我新增一个人,名字叫做Tom,年龄为30,性别为male,家乡为Shanghai,职业为engineer。" +
                    "返回指令:@{\"methods\":\"addPerson\",\"data\":{\"name\":\"Tom\",\"age\":30,\"gender\":\"male\",\"hometown\":\"Shanghai\",\"occupation\":\"engineer\"}}@" +
                    "帮我删除名字为Cathy的人。" +
                    "返回指令:@{\"methods\":\"removePerson\",\"data\":{\"name\":\"Cathy\"}}@" +
                    "帮我查找名字为John的人。" +
                    "返回指令:@{\"methods\":\"findPerson\",\"data\":{\"name\":\"John\"}}@" +
                    "帮我更新名字为Lucy的人的信息,把家乡改为Beijing,职业改为doctor。" +
                    "返回指令:@{\"methods\":\"updatePerson\",\"data\":{\"name\":\"Lucy\",\"hometown\":\"Beijing\",\"occupation\":\"doctor\"}}@",
                role: "assistant"
            }
        ]
    }

    async toChatGPT(question, callback) {
        let str = await this.getList(question, callback);
        this.action(str, callback);
    }

    getList = (question, callback) => {
        return new Promise((resolve) => {
            axios.post('/search/send', {
                message: [
                    ...this.getMemory(),
                    {
                        content: question,
                        role: "user"
                    }
                ],
            }).then((response) => {
                // 请求成功
                resolve(response.data.choices[0].message.content);
            }).catch((error) => {
                // 请求失败,
                callback({
                    result: true,
                    response: "程序错误,请重新请求"
                });
                console.log(error);
            });
        })
    }

    action = (str, callback) => {
        const match = str.match(/@(.*?)@/g);
        console.log("match", match);
        if (match.length) {
            match.map((gptOrder) => {
                const match = gptOrder.match(/@(.*?)@/);
                const result = match ? match[1] : null;
                let json = JSON.parse(result);
                this[json.methods](json.data);
            });
            callback({
                result: true,
                response: "操作成功"
            });
        } else {

            callback({
                result: false,
                response: str
            });
        }
    }
}
export default People;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1944083.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

大屏数据看板一般是用什么技术实现的?

我们看到过很多企业都会使用数据看板&#xff0c;那么大屏看板的真正意义是什么呢&#xff1f;难道只是为了好看&#xff1f;答案当然不仅仅是。 大屏看板不仅可以提升公司形象&#xff0c;还可以提升企业的管理层次。对于客户&#xff0c;体现公司实力和品牌形象&#xff0c;…

Linux shell编程学习笔记66:ping命令 超详细的选项说明

0 前言 网络信息是电脑网络信息安全检查中的一块重要内容&#xff0c;Linux和基于Linux的操作系统&#xff0c;提供了很多的网络命令&#xff0c;今天我们研究最常用的ping命令。 1 ping命令 的功能、格式和选项说明 1.1 ping命令 的功能 简单来说&#xff0c; ping 命令 会…

编写SpringBoot的自定义starter包

starter项目 先来看一下Starter的官方解释&#xff1a; Spring Boot Starter 是一种方便的依赖管理方式&#xff0c;它封装了特定功能或技术栈的所有必要依赖项和配置&#xff0c;使得开发者可以快速地将这些功能集成到Spring Boot项目中。Spring Boot官方提供了一系列的Star…

首次 Cloudberry Database 社区聚会 · 北京站,8月3日,诚邀

近期 Greenplum 源码归档及走向闭源在圈内讨论火热&#xff0c;原有开源用户面临断档风险。作为 Greenplum 衍生版和开源替代&#xff0c;Cloudberry Database 由原厂核心开发者打造&#xff0c;与其保持兼容&#xff0c;并且具备更新内核和更丰富功能。Cloudberry Database 逐…

代理协议解析:如何根据需求选择HTTP、HTTPS或SOCKS5?

代理IP协议是一种网络代理技术&#xff0c;可以实现隐藏客户端IP地址、加速网站访问、过滤网络内容、访问内网资源等功能。常用的IP代理协议主要有Socks5代理、HTTP代理、HTTPS代理这三种。代理IP协议主要用于分组交换计算机通信网络的互联系统中使用&#xff0c;只负责数据的路…

【MATLAB实战】基于UNet的肺结节的检测

数据&#xff1a; 训练过程图 算法简介&#xff1a; UNet网络是分割任务中的一个经典模型,因其整体形状与"U"相似而得名,"U"形结构有助于捕获多尺度信息,并促进了特征的精确重建&#xff0c;该网络整体由编码器,解码器以及跳跃连接三部分组成。 编码器由…

UE4/5 对话系统

参考教程&#xff1a;UE4甜筒教艺术生学蓝图#21.UE4对话系统(1)--唠嗑案例展示_哔哩哔哩_bilibili 说来惭愧两年前看的教程&#xff0c;现在才记录一下&#xff0c;很好的教程推荐大家观看 1.首先创建两个枚举&#xff0c;内容如下 2.创建三个结构体&#xff0c;内容如下 3.再…

SSRF:服务端请求伪造

SSRF漏洞原理 SSRF漏洞通常是因为服务端应用程序提供了从其他服务器获取数据的功能&#xff0c;但未对目标地址或协议进行适当的过滤和限制。攻击者可以通过这个漏洞发送构造好的恶意请求&#xff0c;让服务器以自己的身份去访问其他资源&#xff0c;与文件包含漏洞有些许相似…

遍历dom元素下面的子元素的方法,vue中原始标签的ref得到是该元素的dom及下面包含的子dom,与组件ref是引用不同

研究到这个的目的来源是 想用div 遍历方式 替代之前的table tr td 那种框选功能&#xff0c;觉得div灵活&#xff0c;可以随便在外面套层&#xff0c;td与tr之间就不能加div加了布局就乱&#xff0c;然后使用之前的原理&#xff08; const cellList tableIdR.value.querySelec…

Caché 数据库摘要与手册索引

因为设置了 VIP 可见,对于无法直接阅读该篇博客的,建议直接阅读官方博客,链接如下: Cach & Ensemble 2018.1.4 – 2018.1.9 | Documentation Home Page (intersystems.com)https://docs.intersystems.com/latest/csp/docbook/DocBook.UI.Page.cls 目录 一、简介 0、…

【Socket 编程】应用层自定义协议与序列化

文章目录 再谈协议序列化和反序列化理解 read、write、recv、send 和 tcp 为什么支持全双工自定义协议网络计算器序列化和反序列化 再谈协议 协议就是约定&#xff0c;协议的内容就是约定好的某种结构化数据。比如&#xff0c;我们要实现一个网络版的计算器&#xff0c;客户端…

掌握互联网路由选择协议:从基础入门到实战

文章目录 路由选择协议的基本概念路由选择算法的分类分层次的路由选择协议路由信息协议&#xff08;RIP&#xff09;内部网关协议&#xff1a;OSPF外部网关协议&#xff1a;BGP互联网中的实际应用总结 互联网的路由选择协议是网络通信的核心&#xff0c;它决定了数据包如何在网…

Artix7系列FPGA实现SDI视频编解码+图像缩放+多路视频拼接,基于GTP高速接口,提供4套工程源码和技术支持

目录 1、前言工程概述免责声明 2、相关方案推荐本博已有的 SDI 编解码方案本博已有的FPGA图像缩放方案本博已有的已有的FPGA视频拼接叠加融合方案本方案的无缩放应用本方案在Xilinx--Kintex系列FPGA上的应用本方案在Xilinx--Zynq系列FPGA上的应用 3、详细设计方案设计原理框图S…

nodejs编译报错 集合

目录 一、使用命令编译typescript时报错&#xff0c;报错文件tsconfig.json 二、npm start运行后报错&#xff0c;could not find module 一、使用命令编译typescript时报错&#xff0c;报错文件tsconfig.json npx tsc 报错&#xff1a; Specified include paths were [&…

Layer2区块链扩容方案(1)——总述

写在前面 这篇文章作为一个简单介绍&#xff0c;很多技术只是大致提及或者引用&#xff0c;之后会在详细学习后逐项解释。 补充知识 在了解扩容方案之前&#xff0c;我们最好了解一些相关的知识概念 EVM “EVM” 是“Ethereum Virtual Machine”&#xff08;以太坊虚拟机&…

SSRF学习笔记

1.NAT学习 Nat&#xff08;Network Address Translation&#xff0c;网络地址转换&#xff09;是 一种网络通信技术主要用于将私有网络中的内部IP地址转换成公共网络中的公共IP地址&#xff0c;以实现局域网内部设备访问互联网的功能。具体来说&#xff0c;Nat有以下几个主要…

【Emacs有什么优点,用Emacs写程序真的比IDE更方便吗?】

&#x1f3a5;博主&#xff1a;程序员不想YY啊 &#x1f4ab;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f917;点赞&#x1f388;收藏⭐再看&#x1f4ab;养成习惯 ✨希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出…

分析性能提升40%,阿里云Hologres流量场景最佳实践

在互联网和移动分析时代&#xff0c;流量数据成为了企业洞察用户行为、优化产品决策和提升运营效率的关键资源。流量数据主要来源于用户在使用APP、小程序或访问网站等媒介平台时产生的各种操作行为&#xff0c;如点击、浏览、注册、下单等。这些行为数据通过数据埋点技术被采集…

Python爬虫技术 第10节 requests库

requests 是 Python 中非常流行的 HTTP 库&#xff0c;它使得发送 HTTP/1.1 请求变得简单直观。下面我会通过几个实际案例来详细介绍如何使用 requests 库。 1. 发送 GET 请求 最简单的请求类型就是 GET 请求&#xff0c;通常用于获取网页或其他资源。 import requests# 发送…

大语言模型-RetroMAE-检索预训练模型

一、背景信息&#xff1a; RetroMAE是2022年10月由北邮和华为提出的一种密集检索预训练策略。 RetroMAE主要应用于检索模型的预训练&#xff0c;模型架构为非对称的Encoder-Decode结构。 二、整体结构&#xff1a; RetroMAE的模型架构为非对称的Encoder-Decode结构。 Encod…