搜索​​​​

清除过滤器
文章
Michael Lei · 六月 6, 2023

2023 年全球峰会初体验

大家好! 我相信很多人都希望出席 2023 年全球峰会,但出于某种原因无法出席。以下是对 6 月 4 日和 5 日发生的事情的简要回顾。 尽管正式的开幕式要到周日晚上才会举行,但峰会前的活动还是很精彩的。亮点之一(特别是对于这里的体育爱好者而言)是早上的高尔夫锦标赛和足球(又名足球)比赛。不能说关于足球的任何事情,因为我不在场(如果你在场,请在评论部分发表评论和照片!),但据我所知,这是一场有趣的比赛。我可以告诉你关于高尔夫的事! 比赛从早上 6 点开始,一直持续到下午 2 点左右。一开始天气阴沉,雨刚下完。但几个小时后,太阳出现了,防晒霜也随之出现。让我告诉你,50SPF 感觉不够! 为了让它更有趣,当地的动物群决定也出去玩。 在宣布获奖者并享用午餐后,我们返回 The Diplomat Beach Hotel 参加其他活动。 例如,下午有一场女性活动。 这导致周日的主要活动 - 欢迎酒会!这是看到熟悉的面孔并与同事和朋友取得联系的最佳时机。 例如,英语社区的版主(@Muhammad.Waseem、@Dmitry.Maslennikov、@Irène.Mykhailova): 和法语社区(@Lorenzo.Scalese、@Irène.Mykhailova、@Dmitry.Maslennikov、@Guillaume.Rongier7183): 这是“准备”日。主要内容从周一开始! Terry Ragon 开启了峰会,在他的演讲中提醒大家任何成功的公司都必须创新才能保持相关性。 InterSystems 就是这样的公司之一! 此外,他祝贺大家 InterSystems 成立 45 周年和第 30 届全球峰会!这不是令人兴奋吗?不知道你怎么想,公司成立的时候我还没有出生呢! 开场白之后,第一个主题演讲是关于医疗保健的。其中一点 @Donald.Woodlock 谈到了AI 以及它如何拉近开发人员与客户的距离,而不是相反。 在主题演讲(和午餐)之后,每个人都分散到不同的会议、演讲、会议等。我回到了 Tech Exchange 的开发者社区展位。 如果你在峰会上,别忘了顺路过来——我很乐意给你一些礼物作为简单行动的回报 😘 如果你认识一些还不是社区成员的人,鼓励他们过来也得到一些赃物。此外,请查看全球大师赛- 峰会期间可兑换一些奖励: 还有一些新的(和旧的最爱)奖励!有传言说,我们甚至很快就会有笔记本电脑贴纸! 无论如何,在 DevCom 展位让我有机会与新朋友交谈,并结识其他有空的版主。 @Guillaume.Rongier7183 和@Dmitry.Maslennikov @Lorenzo.Scalese、@Dmitry.Maslennikov 和@Francisco.López1549 如果您对背景中的演示文稿感兴趣,请看这里。 此外,参加 Tech Exchange 意味着我可以关注那里正在进行的所有演示。例如,了解容器 😉 在所有这些兴奋之后,我们都去吃晚餐和演示。 玩游戏,玩得很开心。 这是 2023 年全球峰会的第一个官方日。敬请期待接下来的活动!
文章
Michael Lei · 六月 8, 2023

2023全球峰会,完美收官!期待来年!

嗨社区! 我们已经到了#GlobalSummit23 的尾声——最后一天!这是我们的一天——程序员的一天。今天的主题演讲都致力于开发人员、他们的成长、抱负和创新。 更有趣的是,在主题演讲中,@Dean.Andrews2971谈到了开发者社区等话题。你现在可以在Youtube上观看这部分,或者晚些有更新的版本: 午餐后,出席全球峰会的所有主持人齐聚一堂,参加名为“如何充分利用 InterSystems 开发人员生态系统”的会议。今年参加的人比去年多了很多! @Dean.Andrews2971 谈到了社区、全球大师、开放交流、创意门户的新闻和功能,以及人们如何从中受益。 然后是任何想说几句话的人的开放季节😊 @Dmitry.Maslennikov 英文社区 @José.Pereira 葡语社区 @Muhammad.Waseem 英文社区 西语社区的@Francisco.López1549 法文社区的@Lorenzo Scalese DC 英文社区的@Scott Roth 这是所有在场主持人的照片(从左到右):@José.Pereira、@Muhammad.Waseem、@Djeniffer.Greffin7753、@Scott.Roth、@Dean.Andrews2971、@John.Murray、@Irène.Mykhailova ,@Lorenzo.Scalese,@Francisco.López1549。 多么好的一群人! 我希望在场的每个人都喜欢这 45 分钟。 会议结束后,几乎是最后的冰淇淋和咖啡时间了!但在我看见@Guillaume.Rongier7183完成他关于他最喜欢的主题 Python 的演讲之前。 我们联系了@Dmitry.Maslennikov、@Murray.Oldfield 以及在上述会议期间加入的我们的新社区成员 - @Vladimir.Babarykin。 在最后的告别之后,我真的从 Caelestinus 抓住了@Vita.Tsareva 以上就是全部内容,希望您喜欢我的全球峰会进展情况的故事。 在评论中分享您对全球峰会的看法。您认为 2024 年全球峰会的举办地点是什么?这是一个有趣的话题😀到时候见!
文章
Jingwei Wang · 七月 7, 2023

FAQ常见问题系列 - 互联互通套件基础问题

本篇文章主要介绍互联互通套件的一些基础问题: 基于互联互通套件通过互联互通成熟的测评的实施工作量 电子病历共享文档部分:需要客户将业务系统数据灌入CCH套件SQL模型中 服务部分:在平台做消息改造,或者直接做业务系统接口改造 基于互联互通套件通过电子病例五级+互联互通成熟度测评四级需要的最低人员配备和项目总耗时 需要了医院现有业务系统和人员配备,做进一步评估及分析 目标只是通过互联互通成熟度测评需不需要FHIR 不需要,如果只是过测评,只需要互联互通套件基础版就够了 BI相关功能如何实现 可以使用DeepSee,基于Cubes做数据分析及钻取 如何使用Java进行快速开发 可以使用PEX,支持Java开发,但是如果使用Production,推荐使用内置开发语言ObjectScript,学习成本更低,未来开发新特性能力更强大 有没有自带的ETL工具 InterSystems 互联互通套件中没有ETL工具,但是支持所有ETL工具的连接 发送失败消息是否有记录 所有错误消息都能够在平台监控到,且可以进行转发或者重发 有没有按照单个服务流程进行整个业务流程的修改和查看 平台内所有服务都可以按照类别区分,也可以按照服务查看业务流程,但是没有按照单个服务修改整个业务流程的界面
文章
Louis Lu · 十二月 24, 2023

接收POST请求的Base64 文件

在此文章中将分享,当使用InterSystems IRIS 做后端时如何接收并保存通过POST方式发送过来的 Base64文件。 前后端之间传输文件,我认为较简单的方式是:前端将文件转为Base64格式,调用POST方法并将Base64内容附加在JSON消息中的一个参数中,在JSON消息中的另一个参数可以是文件名,比如消息定义如下: { "fileData": "JVBERi0xLjQKJdPr6eEKMSAwIG...", "fileName": "example.pdf" } 在IRIS中,可以定义一个web application用于处理POST请求,同时定义一个分派类继承于%CSP.REST,在类中定义一个方法,具体保存文件。 代码示例: ClassMethod SaveFile() As %Status { Try { Do ##class(%REST.Impl).%SetContentType("application/json") If '##class(%REST.Impl).%CheckAccepts("application/json") Do ##class(%REST.Impl).%ReportRESTError(..#HTTP406NOTACCEPTABLE,$$$ERROR($$$RESTBadAccepts)) Quit // Reading the body of the http call with the file data set dynamicBody = {}.%FromJSON(%request.Content) set dynamicStream = dynamicBody.%Get("fileData",,"stream<base64") set stream=##class(%Stream.FileBinary).%New() set sc=stream.LinkToFile("/shared/durable/"_dynamicBody.fileName) set sc=stream.CopyFromAndSave(dynamicStream) } Catch (ex) { Do ##class(%REST.Impl).%SetStatusCode("400") Do ##class(%REST.Impl).%WriteResponse(ex.DisplayString()) return {"errormessage": "Client error"} } Quit $$$OK } 下面具体解释下其中较重要的部分: 获取到请求的消息内容,并将其转化为%Library.DynamicAbstractObject对象,这样我们可以后面通过对象的方式进行处理 set dynamicBody = {}.%FromJSON(%request.Content) 下面是比较重要的一步,我们将Base64 转化为 %Stream 类型,我们可以直接通过%Library.DynamicObject类下面的%Get方法实现 set dynamicStream = dynamicBody.%Get("fileData",,"stream<base64") 要注意的一点是,这里我们完全可以绕过了string 常常遇到的MAXSTRING 错误,因为我们直接将Base64转化为stream. 最后,我们在服务器上创建了一个文件,内容来自传进的Base64,文件名也来自于传入的JSON消息 set stream=##class(%Stream.FileBinary).%New() set sc=stream.LinkToFile("/shared/durable/"_dynamicBody.fileName) set sc=stream.CopyFromAndSave(dynamicStream)
文章
Qiao Peng · 十月 9, 2023

英国NHS 基于FHIR的数字健康实践案例和经验教训

英国国民医疗保健服务(NHS)简介 国民医疗保健服务(NHS)是英国的公共资助的医疗保健系统的总称,覆盖英格兰的、苏格兰和威尔士。它是世界上第二大单一付款人医疗保健系统,针对英国常住居民提供免费的、全面的卫生服务。这些卫生服务不仅是医疗服务,还包含社区护理服务、精神健康、临终关怀等。 NHS是最大的分级诊疗体系:先看全科医生或急诊,再由他们转诊到医院看专科医生、住院或者手术。它管理着9千万患者记录和6千5百万份病历;每天有100万的就诊、200万电子处方和75万电子转诊。 NHS有200万员工,是世界最大的、非军队的单一机构。一直被评为让英国人最自豪的英国机构,击败了皇室、武装部队和英国广播公司。 NHS面临的挑战和应对 作为政府买单的全国性医疗保健系统,提高治疗效果、提升效率、降低费用是NHS始终面临的挑战。 NHS广泛使用InterSystems的TrakCare作为电子病历系统以获得统一的、最新的患者视图;使用HealthShare作为医疗机构间健康信息共享和交换平台,合并和共享患者信息、治疗计划和临终愿望计划,让授权的医护人员查看患者完整、及时的护理记录小结;使用InterSystems IRIS医疗行业版支撑包括基于机器学习的辅助决策的创新应用,例如对阿尔茨海默氏症的早期发现与诊断。NHS还提供全国的电子处方服务 - 直接将电子处方发送到患者选择的药房,和电子转诊服务。 但NHS仍有很多纸质流程和众多的旧有系统,数字化程度和数据的互操作能力有限。例如NHS使用了21种不同的电子系统来记录患者的数据。这些系统之间不能很好地沟通,因此治疗患者的医生可能无法了解有效治疗患者所需的所有信息。约十分之一的就诊中,医院和全科医生无法获得患者之前的健康记录。“医院和全科医生通常没能在正确的时间、正确的地点获得正确患者的正确信息。这可能导致错误和事故,从而威胁患者的生命。“ 确保信息使用者在正确的时间、正确的地点获得正确患者的正确信息,是有效决策所需的关键要素。需要获取患者信息的不仅有医生和护士,还包括患者自己。这就是战略性的互操作,它不仅是技术问题,更是一个社会问题。 在COVID-19大流行前,NHS为了实现这些目标,制定了数字化(digitise)、连接(connect)、转型(transform)的数字化转型战略: 将服务数字化:让医疗护理服务提供者和患者在需要时可以安全地访问信息。它承诺到2024年将整个NHS数字化。 将它们连接起来以支持服务集成:连接的健康和护理系统意味着数据可以在 IT 系统、医疗护理提供者和机构之间无缝流动。由此产生的信息洞察有助于根据人群的需求定制服务,实现更有针对性的护理并减少不必要的干预。 通过这些基础实现服务转型:数字技术的真正价值不是来自于将现有实践数字化,而是来自于使用它来彻底改变服务。要设计健康和社会护理服务,以使遭受健康不平等的人受益并其尽可能具有包容性,将确保对健康结果产生最大的积极影响。例如NHS的综合护理计划服务(Coordinate My Care),是一项临床服务,将被动的护理服务转变为计划性护理,将急诊和意外入院转变为离家更近的选择性、计划性、成本更低的护理,将患者被动参加转变为患者主动参与。 COVID-19为NHS带来了新的挑战 - 数字化需求的全面提速。自全球 COVID-19 大流行和国家封锁措施以来,卫生和社会护理提供者都采用数字技术作为护理渠道:虚拟会诊、视频会诊、虚拟COVID-19病房。数字化也已扩展到为患者家中提供 iPad,使他们能够远程进行测试,从而降低暴露于COVID-19的风险并为NHS临床医生节省时间。NHS也计划在未来五年内将面对面门诊预约减少多达三分之一。 所有这一切都对系统的互操作能力和基于互操作能力上的服务创新提出了很高的要求,不仅是功能和法规上的,也是响应速度上的 - 在满足法规和标准的同时快速交付的需求。而FHIR恰逢其时地为NHS的这些需求和数字化转型战略赋能。 NHS的FHIR案例 在英国,INTEROPen是一个开放合作组织,致力于加速制定医疗保健和社会保健领域互操作性的开放标准,建立数字信息无缝流动的健康和护理社区。它由NHS、行业供应商、标准化组织和个人组成, InterSystems 是INTEROPen的创始成员和供应商联席主席。INTEROPen定义并推动采用基于 HL7 FHIR 的开放互操作性标准,它基于FHIR R4建立了英国第一个UK Core的国家级Profile和一系列FHIR实施指南(Implementation Guide),并每年举办四到六场黑客马拉松,使成员组织的开发人员能够测试标准和 API,然后再使用这些标准和 API 来连接基于真实临床场景的系统。 NHS正借助INTEROPen,努力简化不同的标准和流程,让服务创新者获得他们需要的东西,以符合各种技术和临床要求,确保关键信息在正确的时间到达正确的人。 NHS最新的努力都基于FHIR标准和UK Core,并定义了一组开放式 FHIR API,用于所有全科医生系统。基于 FHIR 的互操作性帮助NHS简化和自动化流程,释放宝贵的资源来专注于患者护理。 在FHIR基础上,NHS已经实现了这些服务: 患者服务: 让患者自己就可以查询个人记录、药嘱再配、预约、使用电子转诊服务等。患者可以选择何时何地看专家,实施以来,降低了一半的患者预约爽约风险。电子处方服务将处方数据安全快速地传给患者选择的药房,每年为NHS节省2亿3千万英镑。 患者也可以通过苹果手机的Apple Health应用,使用FHIR API安全、私密地大规模访问他们个人的NHS健康信息。 事件通知: FHIR 消息传递和 InterSystems 技术正在通过NHS网络推动临床事件通知。包括父母在内的用户可以订阅事件并接收每个患者的通知。事件管理系统接收 FHIR 消息、存储它们,并根据订阅偏好通知每个订阅者。事件类型包括疫苗接种、儿科发育里程碑或常规筛查检查等。 信息实时更新: NHS救护车出诊时,除了出诊原因,通常医生对患者的情况一无所知。通过FHIR API,NHS从全科医生系统收集患者信息并提供完整的html版本的小结,让医生在救护车到达前就了解患者的诊断、当前用药、过敏、就诊历史等信息,帮助医生确定更好的处置决定,并评估是否需要住院治疗。 药物管理: 住院时协调用药是困难和耗时的,加上转录用药和过敏信息可能发生的错误,这带来巨大的患者安全风险。 同时,传统的药物清单概念,无论是医生开出的药物清单、药房分配的药物清单,还是患者说他们目前服用的药物清单,它们看起来都一样。而FHIR 引入了一种新的药物管理架构,它的药物模块包括 9 种不同的 FHIR 资源——结构化数据的自描述单元以及对其他资源或数据源的引用。它们允许在不同系统之间进行更有意义和有用的药物信息交换。 使用FHIR药物模块,通过FHIR API,NHS从全科医生系统收集药物和过敏信息: 使用UK Core的 “药物可编码概念”或“药物资源” 传输药物信息 使用UK Core的FHIR剂量语法IG(FHIR Dose Syntax Implementation Guidance)将每剂量的药物量转换为简单的编码量 使用 SNOMED CT 和 NHS的dm+d 字典代码传输药物和过敏/不耐受信息 并及时、准确地将当前用药直接列入InterSystems TrakCare电子病历的患者当前用药列表。对于未编码的药物和过敏数据,InterSystems TrakCare这些信息作为自由文本存储在患者记录中,并允许临床医生将其修正为结构化和编码数据输入 TrakCare。开药时,TrakCare 可视化规则会在有非结构化过敏记录时提醒开药者。 通过这些基于FHIR的药物管理,NHS帮助医生更好、更快地协调住院用药,降低用药错误(这是最常见的医疗错误类型)带来的患者安全风险。 护理平稳过渡: 当患者从医院到护理中心再回到家中继续康复或照料,从一个医生转到另一个医生时,不完整的信息导致治疗连续性不佳、患者安全风险、效率不足、不必要的患者再入院和患者教育失败。NHS颁布了基于FHIR的治疗文档传递标准,它是一个结构化的、编码的文档。当患者从医院、急诊科、门诊预约或择期手术出院时,它由急症医院提供,通过FHIR API发送给全科医生。全科医生直接在患者记录中就可以查看到这些患者信息,无需打开另外的文档查找和阅读,这种及时的信息共享有助于实现不间断的患者护理。 另外,NHS还将FHIR应用在术前评估、知情同意、管理高危慢阻肺等业务场景中。 NHS的经验和教训 NHS在借助FHIR推动战略互操作时给我们带来的经验和教训: 战略互操作不仅是技术问题,更是社会问题 借这个机会转变临床和护理流程、服务 合作 它需要借助合作产生的标准实现,要所有利益相关方一起参与 – 需求方拉动、提供方推动 确保参与方都充分理解需求和标准,并理解标准需要不断进化 临床模型 (需求)-> FHIR Profiles (设计) -> 实施指南 (实施)-> API(实施) 组织测试,用来检验标准 务实 关注在交付有用的事情上 – 它要足够好,但不需要完美,不要过分工程化 尽快试错 很多国家在采纳FHIR,但这个过程会比我们想象的长 不要过分扩展FHIR,先从最小规模的扩展开始
文章
Michael Lei · 六月 14, 2023

使用LangChain 修复 SQL

本文是 SqlDatabaseChain 的简单快速入门(我所做的)。 希望大家会感兴趣。 非常感谢: sqlalchemy-iris 作者@Dmitry Maslennikov 您的项目使我的试验变得可能。 文章脚本使用 openai API,因此请注意不要在外部共享您不打算共享的表信息和记录。 如果需要,可以插入本地模型。 创建一个新的虚拟环境 mkdir chainsql cd chainsql python -m venv . scripts\activate pip install langchain pip install wget # Need to connect to IRIS so installing a fresh python driver python -c "import wget;url='https://raw.githubusercontent.com/intersystems-community/iris-driver-distribution/main/DB-API/intersystems_irispython-3.2.0-py3-none-any.whl';wget.download(url)" # And for more magic pip install sqlalchemy-iris pip install openai set OPENAI_API_KEY=[ Your OpenAI Key ] python 初始测试 from langchain import OpenAI, SQLDatabase, SQLDatabaseChain db = SQLDatabase.from_uri("iris://superuser:******@localhost:51775/USER") llm = OpenAI(temperature=0, verbose=True) db_chain = SQLDatabaseChain.from_llm(llm, db, verbose=True) db_chain.run("How many Tables are there") 错误结果 sqlalchemy.exc.DatabaseError: (intersystems_iris.dbapi._DBAPI.DatabaseError) [SQLCODE: <-25>:<Input encountered after end of query>] [Location: <Prepare>] [%msg: < Input (;) encountered after end of query^SELECT COUNT ( * ) FROM information_schema . tables WHERE table_schema = :%qpar(1) ;>] [SQL: SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = 'public';] (Background on this error at: https://sqlalche.me/e/20/4xp6) ←[32;1m←[1;3mSELECT COUNT(*) FROM information_schema.tables WHERE table_schema = 'public';←[0m>>> 开发者之间的对话 IRIS 不喜欢以分号结尾的 SQL 查询。 现在做什么? ? 想法:我告诉 LangChain 帮我修理SQL如何 太酷了,我们开工吧 !! 测试二 from langchain import OpenAI, SQLDatabase, SQLDatabaseChain from langchain.prompts.prompt import PromptTemplate _DEFAULT_TEMPLATE = """Given an input question, first create a syntactically correct {dialect} query to run, then look at the results of the query and return the answer. Use the following format: Question: "Question here" SQLQuery: "SQL Query to run" SQLResult: "Result of the SQLQuery" Answer: "Final answer here" The SQL query should NOT end with semi-colon Question: {input}""" PROMPT = PromptTemplate( input_variables=["input", "dialect"], template=_DEFAULT_TEMPLATE ) db = SQLDatabase.from_uri("iris://superuser:******@localhost:51775/USER") llm = OpenAI(temperature=0, verbose=True) llm = OpenAI(temperature=0, verbose=True) db_chain = SQLDatabaseChain(llm=llm, database=db, prompt=PROMPT, verbose=True) db_chain.run("How many Tables are there") 结果二 SQLQuery:←[32;1m←[1;3mSELECT COUNT(*) FROM information_schema.tables←[0m SQLResult: ←[33;1m←[1;3m[(499,)]←[0m Answer:←[32;1m←[1;3mThere are 499 tables.←[0m ←[1m> Finished chain.←[0m 'There are 499 tables.' 我就说很快吧 参考资料: https://walkingtree.tech/natural-language-to-query-your-sql-database-using-langchain-powered-by-llms/ https://python.langchain.com/en/latest/modules/chains/examples/sqlite.html#sqldatabasesequentialchain https://python.langchain.com/en/latest/modules/agents/plan_and_execute.html
公告
Claire Zheng · 四月 23

Global Masters 项目自2024年4月26日起暂停服务

InterSystems,我们致力于为您提供最优质的服务,包括我们的Global Master项目。 Global Master项目平台的供应商已经被另一家公司收购,不幸的是,我们无法继续在这个平台上托管我们Global Master项目。我们目前正在评估新的平台供应商,以推动Global Masters Advocate Hub的平稳过渡。 自2024年4月26日起,我们将暂停Global Master项目,以期平稳过度到新平台上。 FAQ: 您的积分、徽章和等级 我们将保存所有截至2024年4月26日的积分、徽章和成就,并将把所有数据迁移到新平台。 您在整个开发者生态中的贡献 在迁移过程中,我们仍然会自动计算对开发者生态系统的所有贡献(帖子、评论、应用程序等)。这些应得的积分和徽章将在新项目启动时添加到您的个人资料中。 奖励 为了提供在迁移过程中兑换奖品的机会,我们计划尽快建立一个专门的奖品网页。但是,我们鼓励您在2024年4月26日之前兑换您计划兑换的奖品(4月26日奖品兑换将停止服务),因为此功能将在一段时间内不可用。 接下来如何? 有关升级的所有信息将在 Discord 和开发者社区相关频道中发布。对于给您带来的不便,我们深表歉意,并将努力尽快完成迁移。 仍有疑问?请联系Global Master支持团队 欢迎通过开发者社区联系 Olga @Olga.Zavrazhnova2637 ,或通过Discord 提问。让我们保持沟通! 我们将尽快同步新平台上线日期! 期待在新平台上与您相见!祝好,Global Masters and Developer Community team
文章
Lilian Huang · 三月 14

教程:将 OpenAI 添加到互操作性生产中

人工智能(AI)最近受到广泛关注,因为它可以改变我们生活的许多领域。更好的计算机能力和更多数据帮助人工智能完成了许多惊人的事情,例如改进医学测试和制造自动驾驶汽车。人工智能还可以帮助企业做出更好的决策,提高工作效率,这也是人工智能越来越流行和广泛应用的原因。如何将 OpenAI API 调用集成到现有的 IRIS 互操作性应用程序中? 前提条件 在本教程中,我们假设您已经拥有一个现有的互操作性产品和一组 OpenAI 凭证来调用 OpenAI API。您可以从以下 GitHub 项目分支下载我们在本教程中使用的代码: https://github.com/banksiaglobal/bg-openai/tree/test-app-original要了解如何获取 OpenAI 凭证,请按照本教程https://allthings.how/how-to-get-your-open-ai-api-key/或打开 OpenAI API 密钥页面并创建一个https://platform .openai.com/api-keys 原始申请 我们的应用程序 AppExchange 可模拟 InterSystems OpenExchange 的发布功能:它可获取包含项目描述、项目徽标和 GitHub URL 的请求,并将其发布到 AppExchange 存储库中。 加入人工智能元素 现在,我们假设管理我们存储库的人注意到一些应用程序开发人员很懒,没有为他们正在发布的应用程序提供简短的摘要或徽标。这就是我们的人工智能朋友可以来救援的地方! 理想的工作流程如下所示: 应用程序接收存储库的 URL、摘要和徽标的 URL 作为输入。 如果摘要为空,则 URL 会被发送到基于 GPT 的模型,该模型解析存储库内容并生成项目的描述性摘要。这一过程可能涉及解析存储库中的README 文件、代码注释和资源库中的其他相关文档,以提取有关项目目的、功能和用途的关键信息。 然后,生成的项目摘要将用作另一个基于 GPT 的模型的输入,该模型的任务是为项目创建徽标。该模型使用描述来理解项目的主题,然后设计一个标志,来直观地代表项目的本质和特征。 应用程序输出的响应包括原始 URL、生成的项目摘要和新创建的徽标。此响应提供了项目的全面概述,以及可用于品牌和营销工作的视觉标识符。 为了实现这种集成,我们将使用业务流程设计器对应用程序的工作流程进行可视化设计。 第1步:安装 首先,我们将使用 ZPM 软件包管理器从 Open Exchange 下载 bg-openai 包: zpm "install bg-openai" 您可以在此处查看此软件包https://openexchange.intersystems.com/package/bg-openai-1并在此处查看其源代码https://github.com/banksiaglobal/bg-openai 这个包基于 @Francisco Lopez 的伟大工作,可在此处https://github.com/KurroLopez/iris-openai进行,有四个小更改:我们更改了类名,以使其更符合标准 IRIS 命名规则;我们添加了新的 SimplePrompt 请求,允许用户非常轻松地发送简单的 AI 文本提示;我们将 Api Key 更改为凭证而不是设置;我们将顶级包名称更改为“Banksia”,以符合公司标准。 第 2 步:设置 OpenAI 运行 为了进一步工作和配置产品,如果您在我们的原始应用程序中使用 Docker 映像,请转到位于以下链接的管理门户: http://localhost:42773/csp/sys/UtilHome.csp 导航到互操作性->[命名空间]->配置->生产并确保我们的原始生产正在运行。 添加一个基于类Banksia.OpenAi.Operation 的新操作,并将其命名为OpenAiOut。使其启用。此操作将与 OpenAI API 服务器进行通信。 操作类:Banksia.OpenAi.Operation 操作名称:OpenAiOut 现在,让我们进行在生产中使用新操作所需的最基本设置:添加 API 密钥和 SSL 配置。 导航至OpenAiOut->设置->基本设置->凭据,然后单击放大镜图标以配置凭证。 填写表单数据并在密码字段中添加 apiKey 。单击“保存”保存数据。您可以根据需要填写ID和用户名字段。 在“凭证”字段中,选择我们之前保存的凭证的ID 。 设置 SSL 配置:创建新的客户端 SSL 配置OpenAiSSL并在下拉列表中选择它。 步骤 3 - 使用业务流程设计器为业务流程添加摘要生成 导航到互操作性 > 业务流程设计器并打开AppExchange.Process商业 单击“打开”进行处理。 根据我们上面描述的算法构建该过程的流程图。下图显示了一个示例实现。 检查是否提供了存储库 URL,如果没有输入描述,我们需要查询 ChatGPT 以创建描述。 (request.Summary= "" ) & (request.GitHubUrl '= "" ) 然后,添加 <Сall> 块并创建一个目标OpenAiOut ,该目标将根据请求的类型调用 OpenAi api。 名称:生成摘要 自定义请求的类型和收到的响应,以及分配操作变量。 请求消息类:Banksia.OpenAi.Msg.SimplePrompt.Request set callrequest.Prompt =“访问下一步将为您提供的网站。在一个段落中描述该项目的主要思想、目标和主要功能。” 设置 callrequest.UserInput = request.GitHubUrl 设置callrequest.Model =“gpt-4” 响应消息类:Banksia.OpenAi.Msg.SimplePrompt.Response 设置 context.summary = callresponse.Content 添加一个 <sync> 步骤来等待响应,在 Calls 字段中添加上一个 <call> 的名称 调用:生成摘要 第 4 步 - 将徽标生成添加到业务流程中 获得存储库描述后,让我们继续下一个逻辑部分 - 徽标生成。让我们检查是否有生成图像的描述,并检查是否没有提供图像 URL。让我们设置以下条件: (request.LogoUrl= "" ) & (request.Summary'= "" ) 配置下一个 <call> 元素,同时将OpenAiOut操作作为目标。 名称:生成徽标 自定义请求的类型和收到的响应。 请求消息类:Banksia.OpenAi.Msg.Images.Request 设置 callrequest.ResponseFormat = "url" 设置 callrequest.Operation = "世代" set callrequest.Prompt = "为以下移动应用程序创建一个简单的应用程序图标:"_request.Summary 设置 callrequest.Size = "256x256" 响应消息类:Banksia.OpenAi.Msg.Images.Response 设置 request.LogoURL = callresponse.Data.GetAt(1).Url 完成我们业务流程的修改后,点击编译按钮。 您可以从以下 GitHub 项目分支下载完成的 OpenAI 集成示例: https://github.com/banksiaglobal/bg-openai/tree/test-app 第 5 步:在生产中测试我们的新业务流程 转到互操作性->配置->生产部分 首先,我们需要重新启动流程以应用所有最新更改,导航到AppProcess->Actions->Restart 。 要测试该流程,请转至AppProcess->Actions->Test。使用 OpenAI API 的 GitHub URL 创建测试消息并通过生产发送: 验证应用程序是否正确接收并处理来自 OpenAI API 的响应。转到Visual Trace查看完整的应用程序周期,并确保在每个流程元素中传输正确的数据。 这是人工智能对我们应用程序徽标的看法: 结论 通过执行以下步骤,您可以使用 InterSystems IRIS 中的业务流程将 OpenAI API 集成到互操作性生产中。 bg-openai 模块对于希望将人工智能融入应用程序的开发人员来说是一个很好的资源。通过简化集成过程,它为利用人工智能的力量增强应用程序开辟了新的可能性。 关于作者 Mariia Nesterenko是 Banksia Global 的认证 IRIS 开发人员,专门从事应用程序开发、数据结构、互操作性和地理空间数据。 关于班克西亚全球 Banksia Global是一家国际精品咨询公司,总部位于澳大利亚悉尼,专门为 InterSystems 技术提供专业服务。我们拥有一支由敬业且经验丰富的专业人士组成的团队,我们很自豪能够成为 InterSystems 的官方首要合作伙伴,并获得授权在全球范围内提供服务。我们对卓越和创新的热情促使我们提供高质量的解决方案,满足客户的独特需求。
文章
王喆 👀 · 九月 21, 2023

IRIS自动安装集群--manifest(安装清单)

前言 生产环境下我们部署和使用IRiS引擎,往往采用其主备镜像模式,虽然此架构简单但是往往我们需要持续在电脑前点击或者操作1到2小时,如果中间有个环节出现了问题有时我们可能需要部署一天. 接下来我分享的是IRIS自带的一个功能帮助我们部署---manifest-安装清单。他的主要使用方式是提前通过配置约定好我们期望的安装设置,在安装的过程中由IRIS程序直接执行脚本,简化IRIS集群的部署,减少运维人员的操作步骤,让我们有更多的精力放在实际项目和业务上。 1 简介 %Installer 实用程序允许您定义描述和配置特定 InterSystems IRIS 配置的安装清单,而不是分步安装过程。为此,我们需要创建一个类,其中包含描述所需配置的 XData 块,使用包含通常在安装期间提供的信息(超级服务器端口、操作系统等)的变量。我们还可以在类中包含一个使用 XData 块生成代码以配置实例的方法。本文提供了安装清单的示例,您可以复制和粘贴这个示例尝试使用。 定义清单后,可以在安装期间、从终端会话或代码调用它。注意:清单必须在 %SYS 命名空间中运行。 2 Manifest的最终成品 此成品展示的是一个一键安装主、备、仲裁的机器命令,此方法的使用可以便捷快速的安装主备环境,其基本每一行都有注释其说明: Include %occInclude /// Classname: App.MirrorInstall <br/> /// Summary: 镜像安装清单 <br/> /// Version: 1.0 <br/> /// Date: 2023年09月13日 14:23:24 <br/> /// Author: 王喆 <br/> Class App.MirrorInstall { XData Install [ XMLNamespace = INSTALLER ] { <Manifest> <!-- 镜像配置 --> <Log Text="镜像名称 " Level="0"/> <Var Name="MirrorName" Value="MIRRORSET" /> <Log Text=" 虚拟IP " Level="0"/> <Var Name="VituralIP" Value="192.168.98.110/24" /> <Log Text="仲裁机IP " Level="0"/> <Var Name="ArbiterNode" Value = "192.168.98.103|2188" /> <Log Text="网卡名称 " Level="0"/> <Var Name="PrimaryNetworkAdapter" Value = "Ethernet0" /> <Log Text="主机IP " Level="0"/> <Var Name="MasterIP" Value = "192.168.98.101" /> <Log Text="主机端口 " Level="0"/> <Var Name="MasterPort" Value = "2188" /> <Log Text="主机名称 " Level="0"/> <Var Name="MasterName" Value = "IRIS01" /> <Log Text="备机网卡名称 " Level="0"/> <Var Name="BackupNetworkAdapter" Value = "Ethernet0" /> <Log Text="备机IP " Level="0"/> <Var Name="BackupIP" Value = "192.168.98.102" /> <Log Text="备机名称 " Level="0"/> <Var Name="BackupName" Value = "IRIS02" /> <Log Text="实例名称 " Level="0"/> <Var Name="InstanceName" Value = "IRISHEALTH" /> <Log Text="镜像模式: 主机1或者备机0 " Level="0"/> <!-- <Var Name="MirrorModel" Value="1" />--> <!-- 安装文件所在的目录 --> <!-- <Var Name="INSTALLERDIR" Value = "D:\deploy" /> --> <!-- 实例所在的安装目录 --> <!-- <Var Name="PRODDIR" Value = "C:\InterSystems\IRISHealth" /> --> <!-- 激活 --> <!-- 通用内存堆的大小。 --> <SystemSetting Name="Config.config.gmheap" Value="1048576"/> <!-- 通用内存堆的大小。 --> <SystemSetting Name="Config.config.locksiz" Value="134217728"/> <!-- 错误日志中的最大条目数。 --> <SystemSetting Name="Config.config.errlog" Value="10000"/> <!-- 用于缓存例程缓冲区的共享内存大小。 --> <SystemSetting Name="Config.config.routines" Value="256"/> <!-- 为 8KB 数据库缓存分配的内存 一般为内存的一半 --> <SystemSetting Name="Config.config.globals8kb" Value="1000"/> <!-- 写入图像日志文件目录。 --> <SystemSetting Name="Config.config.wijdir" Value="D:/cache/wij"/> <!-- 日志文件的主要位置。 --> <SystemSetting Name="Config.Journal.CurrentDirectory" Value="E:/cache/journal"/> <!-- 日志文件的备用位置。 --> <SystemSetting Name="Config.Journal.AlternateDirectory" Value="D:/cache/journal"/> <!-- Caché 清除已完成日志文件之前的天数 --> <SystemSetting Name="Config.Journal.DaysBeforePurge" Value="3"/> <!-- 在此连续备份数后 --> <SystemSetting Name="Config.Journal.BackupsBeforePurge" Value="3"/> <!-- 最大IRISTempSizeAtStart --> <SystemSetting Name="Config.Startup.MaxIRISTempSizeAtStart" Value="10"/> <IfDef Var="INSTALLERDIR"> <Log Text=" 激活 " Level="0"/> <Invoke Class="App.MirrorInstall" Method="ConfigureInstance" CheckStatus="0"> <Arg Value="${INSTALLERDIR},${PRODDIR}"/> </Invoke> </IfDef> <!-- 创建命名空间 --> <Log Text="BKLINIK 命名空间存在与否判断 " Level="0"/> <If Condition='(##class(Config.Namespaces).Exists("BKLINIK")=0)'> <Log Text="不存在开始创建 " Level="0"/> <Namespace Name="BKLINIK" Create="yes" Code="BKLINIKAPP" Ensemble="1" Data="BKLINIKMSG"> <Configuration> <!-- 消息的目录 --> <Database Name="BKLINIKMSG" Dir="D:/DB/BKLINIKMSG" Create="yes"/> <!-- 代码的目录 --> <Database Name="BKLINIKAPP" Dir="D:/DB/BKLINIKAPP" Create="yes"/> <!-- 配置映射 --> <ClassMapping Package="HS" From="HSLIB"/> <ClassMapping Package="HSMOD" From="HSLIB"/> <ClassMapping Package="SchemaMap" From="HSLIB"/> <RoutineMapping Routines="HS.*" From="HSLIB" /> <RoutineMapping Routines="HSMOD.*" Type="INC" From="HSLIB" /> <RoutineMapping Routines="HSMOD.*" From="HSLIB" /> <RoutineMapping Routines="SchemaMap*" Type="INC" From="HSLIB" /> <GlobalMapping Global="%SYS" From="IRISSYS" /> <GlobalMapping Global="%SYS("HealthShare")" From="HSSYS"/> <GlobalMapping Global="EnsHL7.Annotation("HealthShare_2.5")" From="HSLIB" /> <GlobalMapping Global="EnsHL7.Description("HealthShare_2.5")" From="HSLIB" /> <GlobalMapping Global="EnsHL7.Schema("HealthShare_2.5")" From="HSLIB" /> <GlobalMapping Global="IRIS.Msg("HS")" From="HSLIB" /> <GlobalMapping Global="IRIS.Msg("HSErr")" From="HSLIB" /> <GlobalMapping Global="IRIS.Msg("HSFHIRErr")" From="HSLIB" /> <GlobalMapping Global="IRIS.Msg("HSFHIRXErr")" From="HSLIB" /> <GlobalMapping Global="IRIS.MsgNames("HS")" From="HSLIB" /> <GlobalMapping Global="IRIS.MsgNames("HSErr")" From="HSLIB" /> <GlobalMapping Global="IRIS.MsgNames("HSFHIRErr")" From="HSLIB" /> <GlobalMapping Global="IRIS.MsgNames("HSFHIRXErr")" From="HSLIB" /> </Configuration> </Namespace> <Log Text="创建命名空间 BKLINIK 结束" Level="0"/> <Log Text="Production启动" Level="0"/> <Namespace Name="BKLINIK" Create="no"> <Log Text=" 设置web应用程序 " Level="0"/> <CSPApplication Url="/csp/bklinik" Directory="${CSPDIR}bklinik" AuthenticationMethods="64" IsNamespaceDefault="true" Grant="%ALL" /> <CSPApplication Url="/csp/bklinik/services" Description="" Directory="${CSPDIR}bklinik\services" Resource="" Grant="%ALL" Recurse="1" LoginClass="" CookiePath="/csp/bklinik/services" AuthenticationMethods="64"/> <Log Text=" 导入代码 " Level="0"/> <!-- 如果设置了 SourceDir 就加载其中的文件 --> <!-- <IfDef Var="SourceDir"> --> <!-- <Log Text="SourceDir已定义-从脱机安装 ${SourceDir}" Level="0"/>--> <Import File="${INSTALLERDIR}\distr\"/> <!-- 设置命名空间的Production自动启动 前提得有这个--> <!-- <Production Name="BKLINIKPKG.FoundationProduction" AutoStart="1" /> --> <!-- </IfDef> --> <Log Text=" 导入代码成功 " Level="0"/> </Namespace> </If> <Log Text=" 镜像 " Level="0"/> <IfDef Var="MirrorModel"> <Log Text="Master已定义-从脱机安装 ${主机}" Level="0"/> <If Condition='(${MirrorModel}=1)' > <!-- 创建主镜像 --> <Log Text=" 创建主镜像 " Level="0"/> <Invoke Class="App.MirrorInstall" Method="CreateMirror" CheckStatus="0"> <Arg Value="${MirrorName},${VituralIP},${ArbiterNode},${PrimaryNetworkAdapter},${MasterIP},${MasterName}"/> </Invoke> </If> <If Condition='(${MirrorModel}=0)' > <!-- 加入镜像 --> <Log Text=" 加入镜像 " Level="0"/> <Invoke Class="App.MirrorInstall" Method="JoinMirror" CheckStatus="0"> <Arg Value="${MirrorName},${MasterName},${MasterIP},${MasterPort},${BackupNetworkAdapter},${BackupIP},${InstanceName}"/> </Invoke> </If> </IfDef> </Manifest> } /// MethodName: setup <br> /// Summary: 入口点方法,您需要调用,在类编译时,它从清单生成CachéObjectScript代码之后,您可以从终端运行此安装程序: <br> /// Parameter: Set pVars("Namespace")="NewNamespace" /// Set pVars("SourceDir")="C:\deploy\distr\" /// set pVart("MirrorModel")=1 /// Do ##class(App.MirrorInstall).setup(.pVart) <br> /// Return: { Boolean } <br> /// Date: 2023年09月13日 15:39:05 <br> /// Author: 王喆 <br> ClassMethod setup(ByRef pVars, pLogLevel As %Integer = 0, pInstaller As %Installer.Installer, pLogger As %Installer.AbstractLogger) As %Status [ CodeMode = objectgenerator, Internal ] { Quit ##class(%Installer.Manifest).%Generate(%compiledclass, %code, "Install") } /// MethodName: ConfigureInstance <br> /// Summary: 激活的方法 <br> /// Parameter: { Object } <br> /// Return: { %Status } <br> /// Date: 2023年09月13日 14:24:17 <br> /// Author: 王喆 <br> ClassMethod ConfigureInstance(InstallerDir As %String, ProdDir As %String) As %Status { Set tSC = $ZF(-1,"copy "_ InstallerDir _ "\iris.key "_ProdDir_"\mgr\iris.key") Set tSC = ##class(%SYSTEM.License).Upgrade() Set tSC = $ZF(-1,"net start ISCAgent") //do ##class() Quit tSC } /// MethodName: CreateMirror <br> /// Summary: 创建镜像 <br> /// Parameter: { Object } <br> /// Return: { %Status } <br> /// Date: 2023年09月13日 14:24:52 <br> /// Author: 王喆 <br> ClassMethod CreateMirror(MirrorName As %String, VituralIP As %String, ArbiterNode As %String, PrimaryNetworkAdapter As %String, MasterIP As %String, MasterName As %String) As %Status { ZNspace "%SYS" #; Start %Service_Mirror 开启镜像服务 Set tSC = ##class(Security.Services).Get("%Service_Mirror",.properties) Set properties("Enabled")=1 Set tSC = ##class(Security.Services).Modify("%Service_Mirror",.properties) Set MirrorInfo("VirtualAddress") = VituralIP Set MirrorInfo("ArbiterNode") = ArbiterNode If "" '= MasterIP{ Set MirrorInfo("ECPAddress") = MasterIP } If "" '= PrimaryNetworkAdapter{ Set MirrorInfo("VirtualAddressInterface") = PrimaryNetworkAdapter } #; if "" '= MasterName #; Set MasterName = ##class(SYS.Mirror).DefaultSystemName() Try { Set tSC = ##class(SYS.Mirror).CreateNewMirrorSet(MirrorName,MasterName,.MirrorInfo) If $$$ISERR(tSC){ Set errobj = ##class(%Exception.General).%New() Set errobj.Name = "Error #",errobj.Code = $SYSTEM.Status.GetErrorCodes(tSC),errobj.Data = $SYSTEM.Status.GetOneStatusText(tSC,1) Throw errobj } } Catch ex { Write ex.DisplayString() } //Create Mirror Se1t //do ##class(SYS.Mirror). Quit tSC } /// MethodName: JoinMirror <br> /// Summary: 加入镜像 <br> /// Parameter: { Object } <br> /// Return: { %Status } <br> /// Date: 2023年09月13日 14:25:19 <br> /// Author: 王喆 <br> ClassMethod JoinMirror(MirrorName As %String, MasterName As %String, MasterIP As %String, MasterPort As %Integer, BackupNetworkAdapter As %String, BackupIP As %String, InstanceName As %String) As %Status { ZNspace "%SYS" //Start %Service_Mirror Set tSC = ##class(Security.Services).Get("%Service_Mirror",.properties) Set properties("Enabled")=1 Set tSC = ##class(Security.Services).Modify("%Service_Mirror",.properties) If "" '= BackupNetworkAdapter{ Set LocalInfo("VirtualAddressInterface") = BackupNetworkAdapter } If "" '= BackupIP{ Set LocalInfo("ECPAddress") = BackupIP } Try { Set SysName = ##class(SYS.Mirror).DefaultSystemName() Set tSC = ##class(SYS.Mirror).JoinMirrorAsFailoverMember(MirrorName,SysName,InstanceName,MasterIP,MasterPort,.LocalInfo) If $$$ISERR(tSC){ Set errobj = ##class(%Exception.General).%New() Set errobj.Name = "Error #",errobj.Code = $SYSTEM.Status.GetErrorCodes(tSC),errobj.Data = $SYSTEM.Status.GetOneStatusText(tSC,1) Throw errobj } } Catch ex { Write ex.DisplayString() } Quit tSC } } 3 安装清单执行 3.1 前置条件: 特别注意:windows server r2 2012 先安装2022版本的IRIS务必去微软官网下载Windows8.1-KB2999226-x64.msu并安装(必须) 预先安装 Java环境推荐Java8(必须) 服务器磁盘分区得有C盘 D盘 E盘可用(推荐) 部署包解压路径 D:\deploy(可选) 安装浏览器(可选) 3.2安装脚本 以管理员权限运行cmd,进入D://deploy 执行安装程序,其在安装时候就可以配置好镜像: 主机执行: ./IRISHealth-2022.1.2.574.0-win_x64.exe INSTALLERMANIFEST="D:\deploy\distr\MirrorInstall.xml" INSTALLERMANIFESTPARAMS="MirrorModel=1,PRODDIR=C:\InterSystems\IRISHealth,INSTALLERDIR=D:\deploy,GlobalBuffers=32768,RoutineCache=1000" INSTALLERMANIFESTLOGFILE="D:\deploy\mirrorLog.txt" INSTALLERMANIFESTLOGLEVEL="3" 备机执行: ./IRISHealth-2022.1.2.574.0-win_x64.exe INSTALLERMANIFEST="D:\deploy\distr\MirrorInstall.xml" INSTALLERMANIFESTPARAMS="MirrorModel=0,PRODDIR=C:\InterSystems\IRISHealth,INSTALLERDIR=D:\deploy,GlobalBuffers=32768,RoutineCache=1000" INSTALLERMANIFESTLOGFILE="D:\deploy\mirrorLog.txt" INSTALLERMANIFESTLOGLEVEL="3" 脚本解释: ./IRISHealth-2022.1.2.574.0-win_x64.exe // 安装程序 INSTALLERMANIFEST="D:\deploy\distr\MirrorInstall.xml" // 安装清单所在的目录 INSTALLERMANIFESTPARAMS=" // 安装的时候传入的参数 MirrorModel=1, // 1-主机 0-备机 PRODDIR=C:\InterSystems\IRISHealth, // 你想安装的目录 INSTALLERDIR=D:\deploy, // 安装文件所在的目录 GlobalBuffers=32768, // Global内存的大小 RoutineCache=1000" // Routine内存的大小 INSTALLERMANIFESTLOGFILE="D:\deploy\mirrorLog.txt" // 安装时候记录的日志位置 INSTALLERMANIFESTLOGLEVEL="3" // 日志级别 好了以上是我本次分享的关于IRIS关于Manifest的相关内容,本文只对manifest做了示例,具体的如何使用及其步骤在官网中描述的比较清楚,如果有需要大家可以去官网看看。 如果您觉得对你有帮助就给我点个赞吧,感激不尽!!!
文章
Weiwei Gu · 五月 4, 2023

在 Docker 中配置镜像

我们客户的一个共同需求是配置 HealthShare HealthConnect 和 IRIS的高可用性模式。 市场上的其他集成引擎通常被宣传为具有“高可用性”配置,但事实并非如此。通常,这些解决方案与外部数据库一起使用,因此,如果这些数据库未配置为高可用性,当发生数据库崩溃或与它的连接丢失时,整个集成工具将变得不可用。 对于 InterSystems 解决方案,这个问题不存在,因为数据库是工具本身的一部分和核心。 InterSystems 如何解决高可用性问题?深奥的配置会把我们拖入异化和疯狂的漩涡?不!在 InterSystems,我们倾听并处理了您的投诉(正如我们一直努力做的那样 ;)),并且我们已将镜像功能提供给所有用户和开发人员。 镜像 镜像如何工作?这个概念本身非常简单。如您所知,IRIS 和 HealthShare 都使用一个日志系统,该系统记录每个实例的数据库上的所有更新操作。这个日志系统是后来帮助我们在崩溃后恢复实例而不会丢失数据的系统。好吧,这些日志文件在镜像中配置的实例之间发送,允许并保持镜像中配置的实例永久更新。 架构 让我们简要解释一下在 Mirror 中配置的系统架构是什么样的: 在故障转移模式下配置的两个实例: 主动节点——接收所有常规的读/写操作。 被动节点:在读取模式下,它同步接收主动节点产生的任何变化。 0-14个异步实例:你可以使用多个异步实例,它们可以是两种类型: DR 异步(灾难恢复):处于读取模式的节点不是故障转移的一部分,尽管它们可以被手动提升成故障转移节点。如果是这样,它们可以在其他两个故障转移节点发生故障时自动提升为主节点。您的数据更新是异步的,所以不能保证其数据是最新的。 报告异步:异步更新节点,用于 BI 任务或数据挖掘。它们不能升级为故障转移,因为可以对数据执行写入。 ISCAgent:安装在每个实例所在的服务器上。它将负责监视所述服务器实例的状态。这是镜像服务器之间除了直接通信之外的另一种通信方式。 Arbiter:它是一个独立于构成镜像的服务器安装的 ISCAgent,并允许通过监视安装的 ISCAgent 和 IRIS/HealthShare 实例来提高安全性和内部故障转移的控制。它的安装不是必须的。 这是一个由只有两个节点的故障转移形成的镜像的操作: 先前的警告 与本文相关的项目没有允许配置镜像的活动许可证。如果你想尝试,直接给我发邮件或者在文末添加评论,我会联系你。 在 Docker 中部署 对于本文,我们将在 Docker 中建立一个小项目,允许我们设置 2 个故障转移实例和一个Arbiter 。默认情况下,可用于 Docker 的 IRIS 映像已经安装并配置了 ISCAgent,因此我们可以跳过该步骤。有必要配置与来自 Visual Studio Code 的文章关联的项目,因为这将使我们以后可以更轻松地使用服务器文件。 让我们看看我们的 docker-compose.yml 会有什么形式: version: '3.3' services: arbiter: container_name: arbiter hostname: arbiter image: containers.intersystems.com/intersystems/arbiter:2022.1.0.209.0 init: true command: - /usr/local/etc/irissys/startISCAgent.sh 2188 mirrorA: image: containers.intersystems.com/intersystems/iris:2022.1.0.209.0 container_name: mirrorA depends_on: - arbiter ports: - "52775:52773" volumes: - ./sharedA:/shared - ./install:/install - ./management:/management command: --check-caps false --key /install/iris.key -a /install/installer.sh environment: - ISC_DATA_DIRECTORY=/shared/durable hostname: mirrorA mirrorB: image: containers.intersystems.com/intersystems/iris:2022.1.0.209.0 container_name: mirrorB depends_on: - arbiter - mirrorA ports: - "52776:52773" volumes: - ./sharedB:/shared - ./install:/install - ./management:/management command: --check-caps false --key /install/iris.key -a /install/installer.sh environment: - ISC_DATA_DIRECTORY=/shared/durable hostname: mirrorB 可以看到我们定义了3个容器: Arbiter :它对应于将被部署以控制将形成 Mirror Failover 的 IRIS 实例的 ISCAgent(即使图像称为 Arbiter)。当启动容器时,它将执行一个 shell 文件,该文件将启动侦听容器端口 2188 的 ISCAgent。 mirrorA :将部署 IRIS v.2022.1.0.209 映像的容器,稍后我们将其配置为主故障转移节点。 mirrorB :将部署 IRIS v.2022.1.0.209 镜像的容器,稍后我们将其配置为辅助故障转移节点。 当我们执行docker-compose up -d命令时,定义的容器将部署在我们的 Docker 中,它在我们的 Docker 桌面中应该看起来像这样(如果我们从 Windows 执行此操作)。 镜像配置。 部署容器后,我们将继续访问我们将在镜像中配置的实例,第一个将在端口 52775 ( mirrorA ) 上侦听,第二个在 52776 ( mirrorB ) 上侦听。访问用户和密码将是superuser/ SYS 由于实例部署在 Docker 中,我们将有两个选项来配置我们服务器的 IP。第一种是在配置中直接使用我们容器的名称(这是最简单的方法)或检查 Docker 为每个容器分配的 IP(打开控制台并执行返回分配的 IP 的 ifconfig)。为了清楚起见,我们将在示例中使用我们为每个容器指定的名称作为 Docker 中每个容器的地址。 首先,我们将配置我们将用作故障转移活动节点的实例。在我们的例子中,它将是我们所说的mirrorA 。 第一步是启用镜像服务,因此我们将从管理门户访问镜像菜单: System Administration --> Configuration --> Mirror Settings --> Enable Mirror Service并标记Service Enabled检查: 启用服务后,我们可以开始配置我们的活动节点。启用该服务后,您将能够在镜像菜单中看到新选项已启用: 在这种情况下,由于我们还没有创建任何镜像配置,我们必须使用Create Mirror选项创建一个新配置。当我们访问这个选项时,管理门户将打开一个新窗口,我们可以从中配置我们的镜像: 让我们仔细看看每个选项: Mirror Name :我们将用来标识我们的镜像的名称。对于我们的示例,我们将其称为 MIRRORSET 需要 SSL/TLS :对于我们的示例,我们不会使用 SSL/TLS 配置连接,尽管在生产环境中,防止在实例之间没有任何类型的加密的情况下共享日志文件会比操作方便更重要。如果您有兴趣配置它,您可以在文档的以下URL中获得所有必要的信息。 使用 Arbiter :此选项不是强制性的,但强烈推荐,因为它为我们的镜像配置增加了一层安全性。对于我们的示例,我们将选中它并指示我们运行 Arbiter 的 IP。对于我们的示例,IP 将位于容器名称arbiter中。 用户虚拟 IP :在 Linux/Unix 环境中,此选项非常有趣,因为它允许我们为将由我们的镜像管理的活动节点配置虚拟 IP。此虚拟 IP 必须与故障转移节点属于同一子网。虚拟IP的操作非常简单,当主动节点出现故障时镜像会自动在待提升的被动节点所在的服务器上配置虚拟IP。这样,被动节点到主动节点的升级对用户来说将是完全透明的,因为他们将继续连接到同一个 IP,即使它将配置在不同的服务器上。如果您想了解有关虚拟 IP 的更多信息,可以查看文档的此URL 。 其余的配置可以保持原样。在屏幕右侧我们会看到镜像中这个节点的相关信息: Mirror Member Name :这个镜像成员的名称,默认情况下它将采用服务器的名称以及实例的名称。 超级服务器地址:这个节点的超级服务器 IP 地址,在我们的例子中是mirrorA 。 Agent Port :配置了该节点对应的ISCAgent的端口。默认为2188 。 配置必要的字段后,我们可以继续保存镜像。我们可以从镜像监视器(系统操作-->镜像监视器)检查配置情况。 完美,这里我们有了新配置的镜像。如您所见,只有我们刚刚创建的活动节点出现。很好,接下来让我们在故障转移中添加我们的被动节点。我们访问mirrorB管理门户并访问镜像设置菜单。正如我们已经为mirrorA实例所做的那样,我们必须启用镜像服务。我们重复该操作,一旦菜单选项更新,我们将选择Join as Failover 。 这里我们有镜像连接屏幕。让我们简要解释一下每个字段的含义: 镜像名称:我们在创建时为镜像指定的名称,在我们的示例中为MIRRORSET 。 Agent Address on Other System :部署主动节点ISCAgent的服务器IP,对我们来说就是mirrorA。 代理端口:我们创建镜像的服务器的ISCAgent监听端口。默认为2188 。 InterSystems IRIS 实例名称:主动节点上 IRIS 实例的名称。在这种情况下,它与被动节点IRIS的一致。 保存镜像数据后,我们将可以选择定义与我们正在配置的被动节点相关的信息。我们再来看看被动节点可以配置的字段: 镜像成员名称:被动节点将在镜像中使用的名称。默认情况下由服务器名称和实例组成。 超级服务器地址:被动节点中超级服务器的 IP 地址。在这种情况下mirrorB 。 代理端口:我们配置的被动节点服务器上安装的ISCAgent的监听端口。默认为2188 。 SSL/TLS 要求:在此示例中不可配置,我们不使用 SSL/TLS。 镜像私有地址:被动节点的 IP 地址。正如我们所见,在使用 Docker 时,我们可以使用容器名称mirrorB 。 代理地址:安装 ISCAgent 的服务器的 IP 地址。和以前一样, mirrorB 。 我们按照指示保存配置,然后返回到镜像监视器以验证我们是否已正确配置所有内容。我们可以将mirrorA中的主动节点和mirrorB中的被动节点的监视器可视化。让我们看看这两个实例之间的差异。 活动节点mirrorA上的镜像监视器: 被动节点mirrorB上的镜像监视器: 如您所见,显示的信息是相似的,基本上改变了故障转移成员的顺序。选项也不同,让我们看看其中的一些: 主动节点mirrorA : 设置无故障转移:防止在作为其中一部分的任何实例停止的情况下执行故障转移。 降级其他成员:从镜像配置中删除其他故障转移成员(在本例中为mirrorB )。 被动节点mirrorB : Stop Mirror On This Member :停止故障转移被动节点上的镜像同步。 降级为 DR 成员:将此节点从其实时同步故障转移的一部分降级为异步模式下的灾难恢复模式。 完美,我们已经配置了节点,现在让我们看看配置的最后一步。我们必须决定哪些表将成为镜像的一部分,并在两个节点上进行配置。如果您查看与本文相关的 Open Exchange 项目的 README.md,您将看到我们配置和部署了两个通常用于训练的应用程序。当我们启动 Docker 容器时,这些应用程序会自动部署,默认情况下会创建 NAMESPACES 和数据库。 第一个应用程序是COMPANY ,它允许我们保存公司记录,第二个应用程序是PHONEBOOK ,它允许我们添加与注册公司以及客户相关的个人联系人。 让我们添加一家公司: 现在让我们为之前的公司创建个人联系人: 公司数据将在COMPANY数据库中注册,联系人数据在PERSONAL中,这两个数据库都已映射,以便可以从命名空间 PHONEBOOK 访问它们。如果我们检查两个节点中的表,我们将看到在mirrorA中我们有公司和联系人的数据,但在mirrorB中仍然没有任何数据,这是合乎逻辑的。 mirrorA注册的公司: 好的,让我们继续在我们的镜像上配置数据库。为此,从我们的活动节点 ( mirrorA ),我们访问本地数据库管理屏幕(系统管理员-->配置-->系统配置-->本地数据库)并单击添加到镜像选项,我们必须选择从列表中我们要添加的所有数据库并从屏幕上读取消息: 一旦我们将数据库从主动节点添加到镜像中,我们必须对其进行备份或复制数据库文件 (IRIS.dat) 并将它们还原到被动节点上。如果您决定直接复制 IRIS.dat 文件,请记住您必须冻结要复制的数据库中的写入,您可以在文档的以下URL中查看必要的命令。在我们的例子中,没有必要暂停,因为除了我们之外没有人在写入数据。 在复制数据库文件之前,让我们从活动节点的监视器上检查镜像的状态: 让我们看看被动节点: 正如我们所看到的,从被动节点我们被告知,虽然我们在镜像中配置了 3 个数据库,但配置尚未完成。让我们继续将数据库从主动节点复制到被动节点,不要忘记我们必须卸载被动节点的数据库才能进行复制,为此我们将从管理门户访问系统配置—— >数据库并访问它们中的每一个,我们继续卸载它们。 完美的!卸载的数据库。让我们从 Visual Studio Code 访问与本文相关的项目代码,看看我们有 IRIS 安装所在的文件夹, sharedA用于mirrorA和sharedB用于mirrorB 。让我们访问 COMPANY、CUSTOMER 和 PERSONAL 数据库所在的文件夹 ( /sharedA/durable/mgr ),然后继续将镜像中每个数据库的 IRIS.dat 复制到 mirrorB 的相应目录 ( /sharedB/durable/mgr) ). 复制完成后,我们再次挂载mirrorB数据库并从mirrorB中的镜像监视器检查已配置数据库的状态: 答对了!我们的镜像已经识别出数据库,现在我们只需要激活和更新它们。为此,我们将点击Activate操作,然后点击Catchup ,这将在激活后出现。让我们看看他们是如何结束的: 完美,我们的数据库已经在镜像中正确配置,如果我们查询 COMPANY 数据库,我们应该看到我们之前从mirrorA注册的记录: 显然我们的COMPANY数据库中有我们之前在mirrorA中输入的记录,毕竟我们已经复制了整个数据库。让我们继续从mirrorA添加一个新公司,我们将其称为“另一家公司”,然后再次查询 COMPANY 数据库表: 在这里,我们完成了。我们只需要确保我们在镜像中配置的数据库对于被动节点mirrorB处于只读模式: 他们在那里!是只读模式R 。好吧,我们已经配置了镜像并同步了数据库。如果我们的产品正在运行,这不会成为问题,因为镜像会自动负责管理它们,并在主动节点出现故障时在被动节点中启动它们。 非常感谢大家走到这一步!它很长,但我希望你觉得它有用。
文章
姚 鑫 · 十二月 31, 2023

第十一章 创建Callout Library - 使用 J 链接类型传递标准计数字符串

# 第十一章 创建Callout Library - 使用 J 链接类型传递标准计数字符串 # 使用 `J` 链接类型传递标准计数字符串 `iris-callin.h` 头文件定义了计数字符串结构 `IRIS_EXSTR`,表示标准 `IRIS` 字符串。此结构包含一个字符元素数组(`8` 位、`16` 位 `Unicode` 或 `32` 位 `wchar t`)和一个指定数组中元素数量的 `int` 值(最多字符串长度限制): ```java typedef struct { unsigned int len; /* length of string */ union { Callin_char_t *ch; /* text of the 8-bit string */ unsigned short *wch; /* text of the 16-bit string */ wchar_t *lch; /* text of the 32-bit string */ /* OR unsigned short *lch if 32-bit characters are not enabled */ } str; } IRIS_EXSTR, *IRIS_EXSTRP; ``` C Datatype| Input |In/Out |Notes ---|---|---|--- IRIS_EXSTR| 1j or j |1J or J| 8 位国家字符的标准字符串 IRIS_EXSTR |2j or n| 2J or N|16 位 Unicode 字符的标准字符串 IRIS_EXSTR| 4j |4J |32 位字符的标准字符串 wchar_t 字符 `IRIS_EXSTR` 数据结构由 `Callin API`(低级 `InterSystems` 函数调用库)中的函数进行操作。有关详细信息,请参阅使用 `Callin API` 中的“`Callin` 函数参考”。尽管名称相似,`Callin API` 和 `$ZF`标注接口是完全独立的产品)。 以下函数用于创建和销毁 `IRIS_EXSTR` 实例: - `IrisExStrNew[W][H`] — 为字符串分配请求的存储量,并使用长度和指向该结构的值字段的指针填充 `IRIS_EXSTR` 结构。 - `IrisExStrKill` — 释放与 `IRIS_EXSTR` 字符串关联的存储。 这是一个 `Callout` 库,它使用所有三种链接类型来返回数字字符串: ### 使用 `J` 连接传递字符串 以下三个函数均生成一个随机整数,将其转换为最多包含 `6` 位数字的数字字符串,并使用 `J` 链接返回字符串 。 ```java #define ZF_DLL // Required when creating a Callout library. #include #include #include #include int get_sample_L(IRIS_EXSTRP retval) { // 8-bit characters Callin_char_t numstr[6]; size_t len = 0; sprintf(numstr,"%d",(rand()%1000000)); len = strlen(numstr); IRISEXSTRKILL(retval); if (!IRISEXSTRNEW(retval,len)) {return ZF_FAILURE;} memcpy(retval->str.ch,numstr,len); // copy to retval->str.ch return ZF_SUCCESS; } int get_sample_LW(IRIS_EXSTRP retval) { // 16-bit characters unsigned short numstr[6]; size_t len = 0; swprintf(numstr,6,L"%d",(rand()%1000000)); len = wcslen(numstr); IRISEXSTRKILL(retval); if (!IRISEXSTRNEW(retval,len)) {return ZF_FAILURE;} memcpy(retval->str.wch,numstr,(len*sizeof(unsigned short))); // copy to retval->str.wch return ZF_SUCCESS; } int get_sample_LH(IRIS_EXSTRP retval) { // 32-bit characters wchar_t numstr[6]; size_t len = 0; swprintf(numstr,6,L"%d",(rand()%1000000)); len = wcslen(numstr); IRISEXSTRKILL(retval); if (!IRISEXSTRNEW(retval,len)) {return ZF_FAILURE;} memcpy(retval->str.lch,numstr,(len*sizeof(wchar_t))); // copy to retval->str.lch return ZF_SUCCESS; } ZFBEGIN ZFENTRY("GetSampleL","1J",get_sample_L) ZFENTRY("GetSampleLW","2J",get_sample_LW) ZFENTRY("GetSampleLH","4J",get_sample_LH) ZFEND ``` 注意:始终终止 `IRIS_EXSTRP` 输入参数 在前面的示例中,始终调用 `IRISEXSTRKILL(retval)` 以从内存中删除输入参数。即使参数不用于输出,也应该始终这样做。如果不这样做可能会导致内存泄漏。
文章
Jingwei Wang · 八月 30, 2023

使用 SQLAlchemy 将表传输到 IRIS 或从 IRIS 获取表

案例描述 假设您是一名 Python 开发人员或拥有一支训练有素的 Python 专业团队,但您分析 IRIS 中某些数据的期限很紧迫。当然,InterSystems 提供了许多用于各种分析和处理的工具。然而,在给定的场景中,最好使用旧的 Pandas 来完成工作,然后将 IRIS 留到下次使用。对于上述情况和许多其他情况,您可能需要从 IRIS 获取表来管理 InterSystems 产品之外的数据。但是,当您有任何格式(即 CSV、TXT 或 Pickle)的外部表时,您可能还需要以相反的方式执行操作,您需要在其上导入并使用 IRIS 工具。无论您是否必须处理上述问题,Innovatium让我明白,了解更多解决编码问题的方法总是能派上用场。好消息是,从 IRIS 引入表时,您不需要经历创建新表、传输所有行以及调整每种类型的繁琐过程。本文将向您展示如何通过几行代码快速将 IRIS 表转换为 Pandas 数据框架并向后转换。您可以在我的GitHub上查看代码,您可以在其中找到包含本教程每个步骤的 Jupiter Notebook。 从 IRIS 引入一张Table 当然,您应该首先导入该项目所需的库。 import pandas as pd import sqlalchemy as db 下一步将是在 Python 文件和 IRIS 实例之间创建连接。为此,我们将使用 SQLAlchemy 的函数 create_engine(),并以字符串作为参数。该字符串应包含有关操作方法、用户名和密码、实例的主机和端口以及目标命名空间的信息。有关使用 sqlalchemy-iris 的基本概念的更多信息,请查看我之前的一篇文章SQLAlchemy - 在 IRIS 数据库中使用 Python 和 SQL 的最简单方法。 engine = db.create_engine( "iris://_system:SYS@localhost:1972/SAMPLE" ) connection = engine.connect() 然后,我们可以声明将保存数据帧的变量,并在此连接上调用 Pandas 的 read_sql_table() 函数,将表名指定为带有Schema的字符串。您还可以在另一个参数中声明Schema,事实上,这是更好的选择,因为名称字符串上有一个点在某些情况下可能会导致错误。 df = pd.read_sql_table( "NameAge" , connection, schema= "PD" ) 最好仔细检查我们正在使用的表是否存在于我们想要使用的Schema中,当然,首先还要检查是否存在我们需要的Schema。在本文的最后一部分中,您将了解如何执行此操作以及更多提示。从现在开始,如果您有办法使用 Pandas,您可以执行任何您想要的更改和分析,因为您知道该怎么做。探索以下示例以了解其工作原理。 向 IRIS 发送表 在开始之前,让我们更改数据框中的某些内容作为示例。我们可以调整列的值以满足我们的需求(例如,添加行和列等)。经过一番尝试后,我将名称改为小写,并根据现有数据添加了一个新人和一列。您可以查看下图来查看结果。 现在我们可以用一行代码将其发送回 IRIS。我们需要的只是指定引擎和表名。 df.to_sql( "NameAge" , con=engine, schema= "PD" , if_exists= "replace" ) 再次,我们需要将Schema与表名分开放在参数中,以避免一些错误和不良行为。除此之外,if_exists 参数指定如果给定Schema中已经存在同名表时要执行的操作。可能的值为:replace、fail(默认)和append。当然,replace 选项会删除表并使用 SQL 命令创建一个新表,而append 会将数据添加到现有表中。请记住,此方法不会检查重复值,因此使用此属性时要小心。最后,失败值会引发以下错误: 请记住,如果您指定的表名不存在,该函数将创建它。 现在,您可以查询 IRIS 以查看新增内容,或者转至管理门户查看专用于 SQL 的部分。请记住,如果您使用替换值,您应该考虑该类的源代码,因为该方法完全重写了它。这意味着如果您实现了任何方法,则应该将它们保留在超类中。 有关 sqlalchemy-iris 的更多提示 如果您有任何问题无法通过其他社区或论坛中共享的与您的应用程序代码相关的信息来解决,您可能会在本节中找到所需的帮助。在这里您将找到有关如何查找有关engine和dialect的详细信息的提示列表。 方言特有的特征 SQL Alchemy 使用根据您的engine自动选择的dialect。当您使用函数 create_engine() 连接到 IRIS 数据库时,选择的dialect是Dmitry Maslennikov 的 sqlalchemy-iris 。您可以使用engine的dialect属性访问和编辑其功能。 engine = db.create_engine( "iris://_system:SYS@localhost:1972/SAMPLE" ) engine.dialect 通过 VSCode 的 IntelliCode 扩展,您可以从此属性中搜索每个选项,或者在CaretDev 的 GitHub上检查源代码。 检查engine中的可用Schema 该dialect中值得强调的一个特殊函数是 get_schema_names() 函数。注意!如果您想避免代码和迭代中出现错误,以下信息可能对您至关重要。 connection = engine.connect() engine.dialect.get_schema_names(connection) 检查Schema中的可用表 我们来看看类似的情况。您可能还需要了解Schema中的可用表。在这种情况下,您可以使用检查。在引擎上运行函数inspect()并将其保存在变量中。您将使用相同的变量来访问另一个函数 get_table_names()。它将返回一个列表,其中包含指定Schema中的表名称或默认的“SQLUser”。 inspection = db.inspect(engine) inspection.get_table_names(schema= "Sample" ) 此外,如果您想在数据上使用更多 SQL Alchemy 功能,您可以声明一个基础并使其元数据反映引擎中的Schema。 b = db.orm.declarative_base() b.metadata.reflect(engine, schema= "Sample" ) 如果您需要更多信息来解决此问题,请查看SQL Alchemy 文档和sqlalchemy-iris GitHub 存储库。或者,您也可以给我留言或发表评论,我们将一起尝试揭开这个秘密。 最后的考虑因素 本文中的实现方法强调使用 IRIS 实例作为云提供商,并使得可以在不同的基础上进行分析。它可以轻松地同时监控所有这些设备的任何质量问题并比较它们的性能和使用情况。如果您将这些知识与另一篇关于用 Django 制作的门户的文章中描述的开发结合起来,您可以根据需要快速构建一个强大的管理器,用于任意数量的特性和实例。此实现也是将数据从 IRIS 外部移动到构建良好的类的有效方法。由于您可能熟悉 Pandas 中用于处理多种不同语言的其他一些函数,即 CSV、JSON、HTML、Excel 和 Pickle,因此您可以轻松地将 read_sql_table 更改为 read_csv、read_json 或任何其他选项。是的,我应该警告您,某些类型与 InterSystems 的集成不是内置功能,因此可能不是很容易。然而,SQL Alchemy 和 Pandas 的结合在从 IRIS 导出数据时总是会派上用场。因此,在本文中,我们了解到 IRIS 拥有您所需的所有工具,可帮助您进行开发并轻松与系统的现有设备或您的专业知识小工具集成。
文章
Qiao Peng · 三月 17

生成式大语言模型和检索增强生成

近来生成式大语言模型掀起了革命性的AI浪潮。生成式大语言模型是什么原理?我们怎么在业务中利用它? 一. 大语言模型的工作原理 生成式大语言模型是生成式人工智能底层的机器学习模型,是一种用于自然语言处理的深度学习模型。 人工智能、机器学习与大语言模型的关系如下图: 1.1 为什么我们称之为大语言模型? 大语言模型的“大”体现在多个方面: 首先,模型尺寸巨大,尤其是它的参数数量。例如GPT3有1750亿的参数; 其次,大语言模型是在巨大的算力基础上,基于海量语料进行训练的。例如Meta的Llama 2 的训练数据达到了两万亿个词(token); 再次,大语言模型是为解决通用问题,而非特定问题构建的。 1.2 大语言模型是怎么训练的? 大语言模型是事先训练好的模型。 训练时,大语言模型基于各种语料 - 人类知识库(例如Wikipedia)、公共数据集、网络爬虫数据,让模型进行“填空”练习,并经过人工编辑和“校对” 训练出来的,需要成千上万的GPU建立集群进行训练。根据Meta的信息,其Llama 2 的训练数据达到了两万亿个token,上下文长度为4096,对话上也是使用100万人类标记的数据微调。 运行时,训练产生的大语言模型可以在小的多的硬件上运行。 1.3 大语言模型的机器学习算法 冰冻三尺,非一日之寒;滴水穿石,非一日之功。生成式大语言模型能够落地经历了相当漫长的技术积累与进步。 大语言模型使用的机器学习算法是优化过的神经网络(Neural Network)。 神经网络发明于上世纪40-50年代,本质上是一个曲线拟合算法,通过拟合多个、多层的Softplus(曲线)、ReLU(Rectified Linear Unit 折线)、Sigmoid(对数线),实现对任意曲线的拟合。 “神经网络”名字听起来很高大上,但并不是脑科学的产物。因为发明时,觉得算法中每个节点像神经元、每个连线像神经触突,因此称为神经网络。 它很早就应用于自动控制领域。后来发展出多种神经网络算法,例如用于图像识别的卷积神经网络(CNN)、很早就用于语言学习的递归神经网络(RNN)… 在大语言模型成熟前,自然语言处理进化出过众多的技术,例如词袋、词汇矢量化、基于递归神经网络的模型、超长短期记忆网络(LSTM)… 但都在能力和算力上有众多缺陷,无法用于有实用价值的内容生成领域。 虽然它们不能实现实用化的内容生成,但为内容生成式大语言模型落地打下了基础,也是我们了解大语言模型前必须了解的预备知识。 1.3.1 分词(Tokenization) 词汇是语言模型分析的最小语义单位,所以第一步要把语句拆分成词汇(token)。分词并不简单,例如中文语句的分词就无法通过空格区分。所以用于大语言模型的分词算法也是基于海量语料训练出来的。 而基于大语言模型的内容生成,就是基于当前的所有token,预测下一个token,从而产生完整的内容。 1.3.2 词汇和语句的矢量化 机器学习算法基本只能处理数字,无法处理文本、声音、图像等非数字内容。所以要处理语言,需要对语句进行矢量化的表达,将其转换为数字。 拿我们常玩的一个游戏做解释:一个人在头脑里想象一个事物,让另一个人猜。另一个人可以问任何问题,但第一个人只能回答是和否。例如问:是动物吗?答:是;问:是哺乳动物吗?答:不是。问:有脚吗?答:是。 这个游戏的过程就是用不同维度来验证和归类一个事物,最终可以让这个事物在不同的维度上得以表达,即这个事物在一个高维度矢量空间上可以得到一个定位(矢量),同时相近的概念在矢量空间互相接近。 大语言模型通过大规模语料训练用神经网络将每个词汇在一个高维度空间矢量化,得到表达矢量的数组,将词汇矢量化到如下示意的矢量空间中: 这里的矢量化出来的是密集矢量,即每个维度上都不是0,且维度数固定,从而用更少的字节中存在更多的信息,因此在计算上的利用成本更低。相较于稀疏矢量的例子,例如书籍的归类:科学、言情、教育、音乐… ,词汇和语句的矢量结果密集度高的多,因此是密集矢量。 而语句矢量化在词汇矢量化的基础上,要将词汇在句子中的顺序信息加入,从而将“小明追老虎”和“老虎追小明”这两个词汇完全相同但语义完全不同的句子在矢量化输出上能够加以区分。 1.3.3 基于大语言的矢量化模型 将词汇和语句矢量化,是迈向我们如今看到的生成式大语言模型的第二步。 不同的语言矢量化模型生成的密集矢量维度数是不一样的,越高的维度数的密集矢量需要越大的计算资源和越大的内存消耗。下面是一些常见的矢量化语言模型和它们的维度数: 模型 维度数量 BERT (Bidirectional Encoder Representations from Transformers) 768或1024 GPT (Generative Pre-trained Transformer) 768或1600 Word2Vec 300 USE (Universal Sentence Encoder) 512 MiniLM 384 1.3.4 矢量相似度查询 词汇和句子矢量化后,怎么找到相似的词汇和句子? 对两个矢量进行相似度查询,就是计算两个矢量间的“距离”。有很多算法,如下图中所示的这些常见算法。 在大规模、高维度矢量数据库中查找近义词,如果采用与矢量记录逐一计算相似度的方法,将需要巨大的计算量,其效率并不能满足实用的性能需求。 而实际需求并不需要精确的相似度,因此出现了近似近邻算法(Approximate Nearest Neighbors - ANN)解决效率问题。ANN有多种算法,例如Annoy (Approximate Nearest Neighbors Oh Yeah)、 HNSW (Hierarchical Navigable Small World)。 下图是Annoy算法的示意图: 在矢量数据集中随机找2个矢量,计算出一个矢量平面到2个矢量的距离相同,从而将矢量数据集分割成2个空间;然后再在每个空间里重复上面的过程,直到分割后的空间里矢量数量与目标相似度矢量数量一致(例如我们希望得到返回矢量数量为10个以内的相似度结果集,那么如果空间内的矢量数小于等于10,就停止上述过程);从而我们得到一个决策树,今后可以用这个决策树进行矢量相似度查询,显然会快很多。 因为Annoy是基于最初的随机选择的2个矢量开始决策树构建的,如果这2个矢量本身就是高度相似的,那这2个矢量永远不会被一个矢量相似度查询要求同时命中,从而带来显著的误差。怎么办?可以随机多选几组初始矢量,从而形成多棵决策树的决策森林,提高ANN的精度。 可见ANN是大规模矢量检索查询的核心。 1.3.5 生成式大语言模型 递归神经网络(recurrent neural network - RNN)很早就应用到自然语言处理领域,之后出现了RNN改进模型LSTM (Long short-term memory),它们按顺序处理输入语句的词汇,并行能力不足,而且越高阶的神经网络需要的算力越高,达不到实用化的性能需求。 在2017年Google一个小团队(Transformer八子)发表了一篇论文 - Attention Is All You Need, 阐述了一类特殊的神经网络 – 基于注意力(Attention)机制的Transformer。它的注意力机制根据输入数据的长度执行固定步骤的计算,并且对输入数据的词汇(token)是并行计算的,它奠定了实用的生成式大语言模型的基础。这个团队的成员后大多离开了Google,并创立或加入了目前市场上几个主要生成式大语言模型。 在Transformer并行处理能力和越来越强大的GPU并行算力加持下,生成式大语言模型终是水到渠成,可以说是大力出奇迹! 当然Transformer模型具备多个特殊能力支撑内容生成能力。下面这张图解释了Transformer模型的4个核心特性:词汇矢量化(Word Embedding)、词汇在语句中位置的矢量化叠加(Positional Encoding)、自我注意力(Self-Attention)和残值连接(Residual Connections)。可见它其实构建在前面出现的技术基础之上。 借助这个新神经网络模型思路,众多大厂发布了自己的生成式大语言模型,如下面列出的这些著名的大语言模型。它们的宣传中常常强调其百亿级、甚至千亿级的参数: 模型 厂商 参数 GPT OpenAI (Microsoft) 1750亿 Bard/Gemini Google 18亿,32.5亿 PaLM2 Google 3400亿 Llama 2 Meta 70亿,130亿,700亿 Claude 2/3 Anthropic (Amazon) 未披露 Stable Beluga Stability AI 70亿,130亿,700亿 Coral Cohere 未披露 Falcon Technology Innovation Institute 13亿,75亿,400亿,1800亿 MPT Mosaic 70亿,300亿 往往参数规模越大,其生成的内容越精确和越富有创造力。那么这些参数指什么?无论是什么样的大语言模型,它们底层都是神经网络,这些参数主要就是指神经网络中的权重和偏差。 二. 大语言模型应用中的问题和检索增强生成 从机制上,生成式大语言模型并不神秘。虽然它展现出了强大的理解能力甚至“创造力”,但它有以下几个问题: 它的知识来自于训练语料,并不知道所有知识。例如GPT-4 截止训练数据的时间是2022年1月份,对于后来的世界一无所知,更不可能知道您的机构中的未开放数据。 它是基于通用数据训练的,对于特定领域往往训练不足。 它的内容生成机制是使用神经网络逐词预测出回答中的下一个词从而构成完整的语句。因此它本质上不会拒绝回答任何问题,虽然人类限制它回答诸如如何制作病毒类的问题。结合它的“无知”和“创造力”,对不知道的问题,它也能一本正经地胡说八道,这就是生成式大语言模型的“幻觉”。 生成式大语言模型的“幻觉”在目前的应用中非常常见。例如我问了Bing Copilot一个关于“什么是InterSystems IRIS互联互通套件?”的问题,它不懂但没有拒绝回答,而且回答地相当“幻觉”: 如果想在我们自己的业务中直接应用生成式大语言模型,让它提供患者教育,或者回复患者的预约查询、亦或回答患者关于他/她自己的用药注意事项?显然不靠谱。 是不是可以用我们自己的数据进行训练?一来很多大模型都不是开放的,无法自己训练;二来相信大家都没有训练大语言模型的昂贵算力。 怎么解决这个问题? 大语言模型其实有三次“训练”机会: 预先训练就是大语言模型厂商通过海量语料进行的训练,我们干不了; 调优训练需要基于开放的大语言模型,算力成本也不低; 所以我们可以通过“提示”,让生成式大语言模型给我们想要的答案。 我又试了一次让Bing Copilot回答“什么是InterSystems IRIS互联互通套件?”,不过这次,我给了它提示,让它先读读关于InterSystems IRIS互联互通套件介绍的网页。这次它回答得相当到位: 也就是通过合适的提问,把本地数据提示给生成式大语言模型,从而让它可以准确回答而不会产生幻觉。 检索增强生成基于问题先在本地数据检索,将相关结果提示给生成式大语言模型,从而获得靠谱的回答,这就是检索增强生成(Retrieval Augmented Generation – RAG)。 这里的本地数据检索,是基于大语言的矢量相似度检索。所以,需要借助矢量数据库,对本地的数据矢量化保存、并提供基于问题的矢量相似度查询,从而基于问题给出最匹配的本地数据。 这里是完整的检索增强生成流程示意图,分为2个过程: 1. 基于本地数据建立矢量知识库的过程 预先建立知识库, 将本地文档切分成文本段 使用矢量化语言模型对数据矢量化 将矢量保存到矢量知识库 2. 借助本地矢量知识库和外部大语言模型回答问题的过程 使用矢量化模型将问题矢量化 在矢量数据库中检索与问题相关的矢量记录 将匹配的数据(知识)作为上下文组织到完整的问题与提示中,向大语言模型提问。例如提示模版是:请仅使用以下上下文回答问题 从大语言模型得到回答 由此可见,检索增强生成至少需要以下3个技术组件: 矢量数据库 – 用于本地数据的矢量化保存和矢量化查询 矢量化语言模型 – 用于将本地数据和问题矢量化 内容生成语言模型 – 用于基于问题和上下文生成自然语言回答 矢量化语言模型、内容生成语言模型都有很多选择,根据需要可以选择能部署到本地的模型、也可以选择厂商提供的云服务。 而矢量数据库是保存本地知识数据的矢量化版本的,市面上常见的是一些nonSQL的专用数据库,也就是说需要将本地数据迁移到矢量数据库,并专门学习其数据操作的API。 可以预见,生成式大语言模型的能力将迅速进化,但本地的知识和数据并不会以如此快的速度发生变化。因此RAG将本地的知识和数据通过矢量化与生成式大语言模型集成,借助其不断提升的强大能力又无需被任何一个模型绑架,将是一个合理的解决方案。 三. InterSystems IRIS的内容生成架构 InterSystems IRIS是应用在众多行业的通用数据平台,并在2024版本中加入了对矢量存储和查询的支持,无需将IRIS中已经保存的本地知识数据迁移到别的矢量数据库中,从而消除数据迁移时间差、额外部署矢量数据库的运维成本,同时降低敏感数据泄露风险、确保遵循特定行业中对数据迁移监管的要求。而InterSystems IRIS作为一个具有互操作能力的数据平台,可以轻松集成大语言模型,并建立和管理检索增强生成的pipeline,降低RAG的技术实现复杂度。 3.1 IRIS的矢量存储和矢量查询 IRIS提供矢量数据类型,它被完全集成在IRIS多模型的架构中,尤其使用SQL就可以完整使用矢量存储和查询。 例如要创建含有矢量类型字段vec的表: CREATE TABLE t (txt VARCHAR(1000), vec VECTOR(INT, 200)); 向矢量字段vec中插入数据: INSERT INTO t VALUES (‘…’, TO_VECTOR(‘1,2,3,…’, INT)); 这里的矢量数据是需要通过调用矢量化模型产生的。 基于矢量相似度查询最接近的10条记录: SELECT TOP 10 * FROM FROM ( SELECT t.*, VECTOR_DOT_PRODUCT(vec, TO_VECTOR(…)) AS similarity FROM t ) ORDER BY similarity DESC; 3.2 IRIS的矢量索引 IRIS进一步提供了更易使用的矢量索引:无需创建矢量字段,直接在现有数据表上就可以创建声明式的矢量索引,并自动调用集成的矢量化模型,从而使用SQL就可以免代码方式进行开发。 创建矢量索引 – 通过索引对title、author和article这3个字段组合进行矢量化: CREATE INDEX Vec ON MyNews(Title, Author, Article) AS VectorIndex(MODEL=‘BERT’); 执行矢量查询 – 查询与条件最近似的3条记录: SELECT TOP 3 * FROM MyNews WHERE Category = ‘NYT’ ORDER BY MyTable_VecSim(%ID, ‘climate change’); 3.3 基于IRIS构建完整的RAG方案 基于最新发布的InterSystems IRIS 2024.1,和部署到本地的矢量化模型(all-MiniLM-L12-v2)、内容生成模型(llama2),我构建了一个RAG原型: 这里IRIS实例即是保存本地数据的数据平台,也是本地数据的矢量化数据库,从而避免了数据的跨平台迁移。而全SQL的数据操作能力,让构建在自己数据上的检索增强生成方案能快速落地。 现在就把生成式大语言模型集成到您自己的业务中吧!注:本文中的部分图片来自StatQuest、medium、wikipedia和weaviate。
文章
Michael Lei · 七月 3, 2023

基于LangChain的IRIS ChatGPT – 释放大语言模型LLM的全部潜力

你好社区在本文中,我将介绍我的应用程序irisChatGPT ,它是基于LangChain Framework构建的。首先,让我们对框架进行一个简单的概述。 全世界都在谈论ChatGPT以及大型语言模型 (LLM) 如何变得如此强大,并且表现超出预期,提供类似人类的对话。这只是将其应用于每个企业和每个领域的开始! 剩下的最重要的问题是如何将这种能力应用于适合企业需求的特定领域数据和特定场景响应行为。 LangChain为这个问题提供了结构化且有效的答案! LangChain 技术可以帮助实现法学硕士的巨大潜力,通过围绕法学硕士提供抽象层并使法学硕士的使用变得简单有效,从而构建令人惊叹的应用程序。 LangChain 是一个框架,可以快速轻松地开发使用大型语言模型(例如 GPT-3)的应用程序。 然而,该框架引入了额外的可能性,例如,轻松使用外部数据源(例如维基百科)来放大模型提供的功能。我相信你们都可能尝试过使用 Chat-GPT,并发现它无法回答特定日期之后发生的事件。在这种情况下,在维基百科上搜索可以帮助 GPT 回答更多问题。 LangChain结构 该框架分为六个模块,每个模块允许您管理与法学硕士互动的不同方面。让我们看看这些模块是什么。 模型:允许您实例化和使用三种不同类型的语言模型,它们是: 大型语言模型 (LLM):这些能够理解自然语言的基础机器学习模型。它们接受输入中的字符串并在输出中生成字符串。 聊天模型:由 LLM 支持的模型,但专门用于与用户聊天。您可以在这里阅读更多内容。 文本嵌入模型:这些模型用于将文本数据投影到几何空间中。这些模型将文本作为输入并返回数字列表,即文本的嵌入。 提示:提示是我们如何与模型交互以尝试从中获取输出。现在知道如何编写有效的提示至关重要。这个框架模块可以让我们更好的管理提示。例如,通过创建我们可以重用的模板。 索引:最好的模型通常是与一些文本数据相结合的模型,以便为模型添加上下文或解释某些内容。这个模块可以帮助我们做到这一点。 链:很多时候,要解决任务,对 LLM 的单个 API 调用是不够的。该模块允许集成其他工具。例如,一个调用可以是一个组合链,其目的是从维基百科获取信息,然后将此信息作为模型的输入。该模块允许连接多个工具以解决复杂的任务。 内存:该模块允许我们在模型调用之间创建持久状态。能够使用记住过去说过的话的模型肯定会改善我们的应用程序。 代理:代理是一个法学硕士,它做出决定,采取行动,观察其所做的事情,并以这种方式继续,直到完成其任务。该模块提供了一组可以使用的代理。 现在让我们更详细地了解一下如何利用不同的模块来实现代码。 Langchain工作原理 步骤1 :用户向LangChain发送问题第2步 :LangChain将此问题发送至Embedding Model步骤3:嵌入模型将文本转换为向量,文本以向量形式存储在数据库中并返回给LangChain步骤4 :LangChain将这些向量发送到向量数据库(有多个向量数据库,我们在我们的应用程序中使用chroma)步骤5:向量数据库返回前 K 个近似最近邻 ( KNN ) 向量第6步:LangChain 将问题与KNN向量一起发送到大型语言模型 (LLM) (我们在应用程序中使用 OpenAI)步骤7:LLM向Langchain返回答案步骤8:Langchain将答案返回给用户 关于申请 irisChatGPT应用程序利用围绕大型语言模型 (LLM) 构建的最热门 Python 框架LangChain的功能。 LangChain 是一个框架,可以快速轻松地开发使用大型语言模型的应用程序。应用程序是在系统间嵌入式 Python功能的帮助下使用 objectscript 构建的。它还包含Streamlit Web 应用程序,这是一个开源 Python 应用程序框架,用于为数据科学和机器学习创建漂亮的 Web 应用程序。 特征 以下是应用程序功能列表以及相关屏幕截图 内置Intersystems ObjectScript 参考ChatGPT 内置InterSystems 大奖赛 2023 ChatGPT 使用 SQLDatabaseChain 回答有关缓存数据库的问题 创建您自己的 chatGPT 模型并与其聊天 OpenAI 聊天GPT 维基百科搜索 使用DuckDuckGo(DDG)通用搜索引擎在互联网上搜索 使用Python REPL LangChain功能生成Python代码 Streamlit Web 应用程序在线演示 谢谢
文章
Qiao Peng · 十二月 7, 2023

通用TCP业务服务和业务操作

TCP作为OSI 7层的传输层的通信协议,其使用上不像更上层的通信协议那么方便,因为TCP操作的不是数据包,它操作的是数据流。因此有多种将TCP数据流“解释”为数据包(消息)的方法。 InterSystems IRIS提供了多种TCP适配器,用于不同的“解释”,例如EnsLib.TCP.FramedInboundAdapter使用特定的首尾字符做为分隔、EnsLib.TCP.CountedInboundAdapter使用固定的长度进行分隔... 同时,InterSystems IRIS提供了多种开箱即用的TCP业务服务和业务操作,方便接入和发送TCP数据。这里我们介绍常见的使用特定的首尾字符做为分隔的TCP业务服务和业务操作。 1. 通用TCP业务服务和业务操作 EnsLib.TCP.Framed.PassthroughService和EnsLib.TCP.Framed.PassthroughOperation是一组使用特定的首尾字符做为分隔TCP数据流的通用业务服务和业务操作。EnsLib.TCP.Framed.PassthroughService业务服务会将TCP数据封装在Ens.StreamContainer发送给业务流程或业务操作;而EnsLib.TCP.Framed.PassthroughOperation业务操作发送并接收Ens.StreamContainer类型的数据。 2. 使用EnsLib.TCP.Framed.PassthroughService业务服务 2.1 向production中加入通用TCP业务服务 增加通用TCP业务服务,只需要在Production配置页面的服务中添加EnsLib.TCP.Framed.PassthroughService。 建议加入Production时,给业务服务起一个名字,用于代表具体的业务,例如是连接到设备的TCP服务,可以命名为TCPforDevice(可以考虑的命名规则 - 接口方式+业务系统)。如果未命名,默认会使用类名作为业务服务名。 2.2 配置通用TCP业务服务 主要的设置项是以下几个: 1. Port:接收TCP数据的端口,例如图中的65530端口 2. Target Config Names:TCP服务发送消息的目标,可以是业务流程或业务操作 3. Message Frame Start:标记TCP开始的字符或字符串,用10进制ASCII码表示。如果有多个字符,字符ASCII间用逗号分隔。图例中为ASCII 10,也就是“退格符”。 4. Message Frame End:标记TCP结束的字符或字符串,用10进制ASCII码表示。如果有多个字符,字符ASCII间用逗号分隔。图例中为ASCII 28和13,也就是“文件分隔符”和“回车符”。 5. Remove Framing: 是否把标记TCP起止的字符删除后再发送到后续业务组件。建议选中 6. Discard Incorrect Framing:丢弃使用不正确起始字符的TCP数据。建议在调试阶段取消选中,测试完成后再选中 7. Frame Acknowledgement:是否要发送Frame 通知,可以取消选中 启用该业务服务后,既可以接收了TCP请求了。 2.3 测试通用TCP业务服务 可以使用TCP客户端进行发送数据的测试。这里使用Packet Sender向IRIS发布的65530端口,发送以下的数据,注意前后的TCP分段起止字符: 然后就可以到消息可视化追踪的页面查看接收的消息。可以看到它是Ens.StreamContainer类型的消息,而且已经把起止字符去掉了: 3. 使用EnsLib.TCP.Framed.PassthroughOperation业务操作 3.1 向production中加入通用TCP业务操作 同样,可以直接将EnsLib.TCP.Framed.PassthroughOperation加入production。 3.2 配置通用TCP业务操作 主要的设置项是以下几个: 1. IP Address:TCP服务器的IP地址 2. Port:TCP服务器的TCP端口,例如图中的65530端口。这里用65530端口,就是发送到上面我们建立的通用TCP业务服务。 3. Message Frame Start:标记TCP开始的字符或字符串,用10进制ASCII码表示。如果有多个字符,字符ASCII间用逗号分隔。图例中为ASCII 10,也就是“退格符”。业务操作会自动在发送的TCP数据头部加入这些开始字符。 4. Message Frame End:标记TCP结束的字符或字符串,用10进制ASCII码表示。如果有多个字符,字符ASCII间用逗号分隔。图例中为ASCII 28和13,也就是“文件分隔符”和“回车符”。业务操作会自动在发送的TCP数据尾部加入这些开始字符。 5. Remove Framing: 是否把收到的TCP响应数据中标记TCP起止的字符删除。建议选中 6. Discard Incorrect Framing:丢弃使用不正确起始字符的TCP响应数据。建议在调试阶段取消选中,测试完成后再选中 启用该业务操作后,既可以发送TCP请求了。 3.3 测试通用TCP业务操作 因为TCP业务操作的请求消息是Ens.StreamContainer,里面是流数据,为了方便测试,我们建立一个测试用的业务流程,里面组织好数据并调用通用TCP业务操作。 3.3.1 创建一个新的业务流程,设置其请求消息为Ens.StringRequest,用于测试时传入TCP数据。并为其上下文增加一个名为DataBody、类型为%Stream.GlobalCharacter(可持久化的字符流类型)的属性: 3.3.2 在业务流程中增加一个代码流程(<code>),将请求消息的字符串数据写入上下文的DataBody字符流: Do context.DataBody.Write(request.StringValue) 注意行首加空格。 3.3.3 然后在业务流程中再加入一个调用流程(<call>),调用上面已经加入production的业务操作,例如TCPtoWMS,并设置请求和响应消息为Ens.StreamContainer或Ens.StreamContainer。 3.3.4 配置RESTtoLIS业务操作的请求消息(Request) 可以直接点击构建请求消息(Request Builder)按钮,使用图形化拖拽建立请求消息: 将左边上下文context里的DataBody拖拽到callrequest的Stream属性上。 3.3.5 将业务流程编译后加入到Production。 3.3.6 测试这个业务流程,输入测试字符串。然后查看消息追踪,可以看到类似这样的: 这是测试业务流程/业务操作的消息追踪: 因为TCP数据发给了同一个production下的通用业务服务,因此还会看到这样的一笔业务服务的消息追踪: